/* KInterbasDB Python Package - Implementation of Parameter Conversion ** ** 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 _kinterbasdb.c, ** without the involvement of a header file. */ /******************** CONVENIENCE DEFS:BEGIN ********************/ #define INPUT_OK 0 #define INPUT_ERROR -1 #define NUMBER_OF_DECIMAL_PLACES_FROM_SCALE(scale) (-(scale)) /* Macros to determine whether a field is a fixed point field based on the ** data_type, data_subtype, and scale. Because the Firebird C API is a ** monstrosity, this must be done separately for array fields. */ #ifdef INTERBASE6_OR_LATER #define _DATA_TYPE_IS_INT64_CONVENTIONAL(data_type) (data_type == SQL_INT64) #define _DATA_TYPE_IS_INT64_ARRAY(data_type) (data_type == blr_int64) #else #define _DATA_TYPE_IS_INT64_CONVENTIONAL(data_type) (FALSE) #define _DATA_TYPE_IS_INT64_ARRAY(data_type) (FALSE) #endif #define IS_FIXED_POINT__CONVENTIONAL(dialect, data_type, data_subtype, scale) \ (boolean)(( \ (data_subtype != SUBTYPE_NONE || scale != 0) \ && ( data_type == SQL_SHORT \ || data_type == SQL_LONG \ || _DATA_TYPE_IS_INT64_CONVENTIONAL(data_type) \ ) \ ) || ( \ /* Special case for fixed-point values with precisions between 10 and 18 \ ** in dialect < 3 databases, which are stored internally as double. */ \ (dialect < 3 && scale != 0 && \ (data_type == SQL_DOUBLE || data_type == SQL_D_FLOAT) \ ) \ )) #define IS_FIXED_POINT__ARRAY_EL(dialect, data_type, data_subtype, scale) \ (boolean)(( \ (data_subtype != SUBTYPE_NONE || scale != 0) \ && ( data_type == blr_short \ || data_type == blr_long \ || _DATA_TYPE_IS_INT64_ARRAY(data_type) \ ) \ ) || ( \ /* Special case for fixed-point values with precisions between 10 and 18 \ ** in dialect < 3 databases, which are stored internally as double. */ \ (dialect < 3 && scale != 0 && \ (data_type == blr_double || data_type == blr_d_float) \ ) \ )) #define TRY_INPUT_CONVERSION(conversion_code, _label) \ if (INPUT_OK != (conversion_code)) { goto _label; } /******************** CONVENIENCE DEFS:END ********************/ static const char *get_external_data_type_name(const unsigned short dialect, const short data_type, const short data_subtype, const short scale ); static const char *get_internal_data_type_name(short data_type); #include "_kiconversion_type_translation.c" #include "_kiconversion_from_db.c" #include "_kiconversion_blob.c" #include "_kiconversion_to_db.c" #include "_kiconversion_array.c" #define PyObject2XSQLVAR_TRY_INPUT_CONVERSION(conversion_code) \ TRY_INPUT_CONVERSION( (conversion_code), PyObject2XSQLVAR_FAIL ); static int PyObject2XSQLVAR( CursorObject *cursor, XSQLVAR *sqlvar, PyObject *py_input ) { int status = INPUT_ERROR; PyObject *py_input_converted = NULL; const short data_type = XSQLVAR_SQLTYPE_IGNORING_NULL_FLAG(sqlvar); const short data_subtype = sqlvar->sqlsubtype; const short scale = sqlvar->sqlscale; const unsigned short dialect = cursor->connection->dialect; assert (py_input != NULL); /* With input parameters, we don't know beforehand just how much space the ** incoming value might take up (because of implicit parameter conversion). ** Therefore, we must allocate+free an input buffer each time we receive an ** individual incoming parameter value, rather than preallocating an input ** buffer for all input XSQLVARs (as kinterbasdb 3.0 did), or even allocating ** an input buffer for the life of a single input XSQLVAR. */ assert(sqlvar->sqldata == NULL); /* Space for the sqlind flag should already have been allocated in ** reallocate_sqlda. */ assert (sqlvar->sqlind != NULL); /* Give the registered dynamic type translator a chance to convert the input ** value before it's passed to the storage code. ** Arrays are excluded because conceptually, they're just containers. Their ** individual elements will be passed through the type translator in ** kiconversion_array.c */ if (data_type == SQL_ARRAY) { py_input_converted = py_input; /* Artificially incref py_input_converted because it's not actually a new ** reference returned from a converter. */ Py_INCREF(py_input_converted); } else { /* Find the dynamic type translation converter (if any) for this field's type. */ PyObject *converter = cursor_get_in_converter( cursor, data_type, data_subtype, scale, FALSE /* not an array element */ ); if (converter == NULL) { goto PyObject2XSQLVAR_FAIL; } py_input_converted = dynamically_type_convert_input_obj_if_necessary( py_input, FALSE, /* not an array element */ dialect, data_type, data_subtype, scale, converter ); if (py_input_converted == NULL) { goto PyObject2XSQLVAR_FAIL; } /* py_input_converted is now a new reference that must be released at the ** end of this function. */ } assert (py_input_converted != NULL); /* If the input value is None, ensure that the destination field allows NULL ** values. If it does, set the XSQLVAR's NULL flag and return immediately; ** no further conversion is necessary. */ if (py_input_converted == Py_None) { if ( XSQLVAR_IS_ALLOWED_TO_BE_NULL(sqlvar) ) { /* Set sqlind to INDiciate to the DB engine that that provided value is ** null. */ XSQLVAR_SET_NULL(sqlvar); assert(sqlvar->sqldata == NULL); /* sqldata was null and will remain so. */ goto PyObject2XSQLVAR_SUCCEED_ALLOW_NULL; } else { char *err_msg = NULL; #if PYTHON_2_2_OR_LATER #define CLEAN_UP_MSG_COMPONENTS() \ Py_XDECREF(formatted_msg); \ Py_XDECREF(rel_name); \ Py_XDECREF(field_name); \ Py_XDECREF(field_id); #define CHECK_FOR_MEM_ERROR_WHILE_ASSEMBLING_NULL_ERROR(ptr) \ if (ptr == NULL) { \ CLEAN_UP_MSG_COMPONENTS(); \ PyErr_NoMemory(); \ goto PyObject2XSQLVAR_FAIL; \ } PyObject *formatted_msg = NULL; { /* formatted_msg composition block : begin */ PyObject *field_id = NULL; /* XSQLVAR.relname/sqlname, etc are not null-terminated; their lengths ** are specified by the corresponding *_length field. */ PyObject *rel_name = NULL; PyObject *field_name = NULL; if (sqlvar->relname_length > 0) { rel_name = PyString_FromStringAndSize(sqlvar->relname, sqlvar->relname_length); CHECK_FOR_MEM_ERROR_WHILE_ASSEMBLING_NULL_ERROR(rel_name); } if (sqlvar->aliasname_length > 0) { field_name = PyString_FromStringAndSize(sqlvar->aliasname, sqlvar->aliasname_length); CHECK_FOR_MEM_ERROR_WHILE_ASSEMBLING_NULL_ERROR(field_name); } if (rel_name != NULL && field_name != NULL) { field_id = PyString_FromFormat(" %s.%s ", PyString_AS_STRING(rel_name), PyString_AS_STRING(field_name) ); } else if (field_name != NULL) { field_id = PyString_FromFormat(" %s ", PyString_AS_STRING(field_name)); } else { field_id = PyString_FromString(" "); } CHECK_FOR_MEM_ERROR_WHILE_ASSEMBLING_NULL_ERROR(field_id); formatted_msg = PyString_FromFormat( "Database parameter or field%scannot be NULL, so Python's" " None is not an acceptable input value.", PyString_AS_STRING(field_id) ); CHECK_FOR_MEM_ERROR_WHILE_ASSEMBLING_NULL_ERROR(formatted_msg); Py_XDECREF(rel_name); Py_XDECREF(field_name); Py_XDECREF(field_id); } /* formatted_msg composition block : end */ err_msg = PyString_AS_STRING(formatted_msg); #else /* not PYTHON_2_2_OR_LATER */ err_msg = "Database parameter or field cannot be NULL, so Python's" " None is not an acceptable input value."; #endif /* PYTHON_2_2_OR_LATER */ assert (err_msg != NULL); raise_exception(DataError, err_msg); #if PYTHON_2_2_OR_LATER Py_DECREF(formatted_msg); #endif goto PyObject2XSQLVAR_FAIL; } } /* It is now certain the sqlvar will not represent a NULL value; make that ** understanding explicit. */ XSQLVAR_SET_NOT_NULL(sqlvar); switch (data_type) { case SQL_VARYING: /* (SQL_VARYING -> VARCHAR) */ case SQL_TEXT: /* (SQL_TEXT -> CHAR) */ PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_text_conventional(py_input_converted, sqlvar, data_type) ); break; case SQL_SHORT: case SQL_LONG: #ifdef INTERBASE6_OR_LATER case SQL_INT64: #endif /* INTERBASE6_OR_LATER */ PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_internal_integer_types_conventional(py_input_converted, sqlvar, dialect, data_type, data_subtype, scale ) ); break; case SQL_FLOAT: PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_float_conventional(py_input_converted, sqlvar) ); break; case SQL_DOUBLE: case SQL_D_FLOAT: PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_double_conventional(py_input_converted, sqlvar) ); break; /* Handle TIMESTAMP, DATE, and TIME fields: */ case SQL_TIMESTAMP: /* TIMESTAMP */ PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_timestamp_conventional(py_input_converted, sqlvar) ); break; #ifdef INTERBASE6_OR_LATER case SQL_TYPE_DATE: /* DATE */ PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_date_conventional(py_input_converted, sqlvar) ); break; case SQL_TYPE_TIME: /* TIME */ PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_time_conventional(py_input_converted, sqlvar) ); break; #endif /* INTERBASE6_OR_LATER */ case SQL_BLOB: PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_blob(cursor, sqlvar, py_input_converted) ); break; case SQL_ARRAY: /* Array support new on 2002.12.23. */ /* In the SQL_ARRAY case, the input object has not actually been passed ** through a dynamic type translator, and it never will be, because it's ** merely a container (a Python sequence). However, dynamic type ** translation *is* applied to each of the input sequence's elements in ** conv_in_array. */ PyObject2XSQLVAR_TRY_INPUT_CONVERSION( conv_in_array( py_input_converted, (ISC_QUAD **) &(sqlvar->sqldata), cursor, sqlvar->relname, sqlvar->relname_length, sqlvar->sqlname, sqlvar->sqlname_length ) ); break; default: raise_exception( NotSupportedError, "SQL type is currently not supported " KIDB_REPORT " " KIDB_HOME_PAGE ); goto PyObject2XSQLVAR_FAIL; } /* end of switch */ /* Fall through to success. */ assert (sqlvar->sqldata != NULL); PyObject2XSQLVAR_SUCCEED_ALLOW_NULL: /* As in the case of py_input == None. */ status = INPUT_OK; goto PyObject2XSQLVAR_CLEANUP; PyObject2XSQLVAR_FAIL: status = INPUT_ERROR; if (sqlvar->sqldata != NULL) { kimem_main_free(sqlvar->sqldata); sqlvar->sqldata = NULL; } PyObject2XSQLVAR_CLEANUP: /* 2003.09.06b: begin block: */ if (py_input_converted != NULL && PyString_Check(py_input_converted)) { /* If py_input_converted is a string, sqlvar->sqldata contains only a ** pointer to py_input_converted's internal character buffer, not a pointer ** to a copy of the buffer. Therefore, we must ensure that ** py_input_converted is not garbage collected until the database engine ** has had a chance to read its internal buffer. */ assert(cursor->objects_to_release_after_execute != NULL); if ( PyList_Append(cursor->objects_to_release_after_execute, py_input_converted) != 0 ) { Py_DECREF(py_input_converted); return INPUT_ERROR; /* PyList_Append will have already set an exception. */ } /* Decref py_input_converted so that if it was a new string object created ** by an input-dynamic-type-translator, the only remaining reference to it ** will then be held by cursor->objects_to_release_after_execute. ** When cursor->objects_to_release_after_execute is released in ** free_XSQLVAR_dynamically_allocated_memory (which is called at the end of ** pyob_execute), py_input_converted will be released as a consequence. */ Py_DECREF(py_input_converted); } else { /* If py_input_converted was any other type of *new* input-dynamic-type- ** translator-created object than a string, it can be released right now, ** because sqlvar->sqldata now contains an independent C-level *copy* of the ** input value. ** If there was no relevant dynamic type translator, py_input_converted *is* ** py_input with an artificially incremented reference count, so it's still ** proper to decref it here. */ Py_XDECREF(py_input_converted); } /* 2003.09.06b: end block */ return status; } /* PyObject2XSQLVAR */ static const char *get_external_data_type_name(const unsigned short dialect, const short data_type, const short data_subtype, const short scale ) { switch (data_type) { case SQL_TEXT: return "CHAR"; case SQL_VARYING: return "VARCHAR"; case SQL_SHORT: case SQL_LONG: #ifdef INTERBASE6_OR_LATER case SQL_INT64: #endif /* INTERBASE6_OR_LATER */ switch (data_subtype) { case SUBTYPE_NONE: /* The database engine doesn't always set data_subtype correctly, ** so call IS_FIXED_POINT__CONVENTIONAL to second-guess the engine. */ if (IS_FIXED_POINT__CONVENTIONAL(dialect, data_type, data_subtype, scale)) { return "NUMERIC/DECIMAL"; } else { switch (data_type) { case SQL_SHORT: return "SMALLINT"; case SQL_LONG: return "INTEGER"; #ifdef INTERBASE6_OR_LATER case SQL_INT64: return "BIGINT"; #endif /* INTERBASE6_OR_LATER */ } } case SUBTYPE_NUMERIC: return "NUMERIC"; case SUBTYPE_DECIMAL: return "DECIMAL"; } case SQL_FLOAT: return "FLOAT"; case SQL_DOUBLE: case SQL_D_FLOAT: return "DOUBLE"; case SQL_TIMESTAMP: return "TIMESTAMP"; #ifdef INTERBASE6_OR_LATER case SQL_TYPE_DATE: return "DATE"; case SQL_TYPE_TIME: return "TIME"; #endif /* INTERBASE6_OR_LATER */ case SQL_BLOB: return "BLOB"; default: return "UNKNOWN"; } } /* get_external_data_type_name */ static const char *get_internal_data_type_name(short data_type) { switch ( data_type ) { case SQL_TEXT: return "SQL_TEXT"; case SQL_VARYING: return "SQL_VARYING"; case SQL_SHORT: return "SQL_SHORT"; case SQL_LONG: return "SQL_LONG"; #ifdef INTERBASE6_OR_LATER case SQL_INT64: return "SQL_INT64"; #endif /* INTERBASE6_OR_LATER */ case SQL_FLOAT: return "SQL_FLOAT"; case SQL_DOUBLE: case SQL_D_FLOAT: return "SQL_DOUBLE"; case SQL_TIMESTAMP: return "SQL_TIMESTAMP"; #ifdef INTERBASE6_OR_LATER case SQL_TYPE_DATE: return "SQL_TYPE_DATE"; case SQL_TYPE_TIME: return "SQL_TYPE_TIME"; #endif /* INTERBASE6_OR_LATER */ case SQL_BLOB: return "SQL_BLOB"; default: return "UNKNOWN"; } } /* get_internal_data_type_name */ int PyObject2XSQLDA ( CursorObject *cursor, XSQLDA *sqlda, PyObject *params ) { /* Assumption: the type of argument $params has already been screened by ** pyob_execute; we know it is a sequence. */ short num_required_statement_params = sqlda->sqld; short num_supplied_statement_params = PySequence_Size(params); int conversion_status; int i; PyObject *cur_param; XSQLVAR *cur_sqlvar; OriginalXSQLVARSpecificationCache *cur_spec_cache; /* For the sake of the safety of free_XSQLVAR_dynamically_allocated_memory ** in case this function encounters a conversion error, do an initial pass ** to set the appropriate pointers to NULL. */ for ( i = 0, cur_sqlvar = sqlda->sqlvar, cur_spec_cache = cursor->in_var_orig_spec; i < num_required_statement_params; i++, cur_sqlvar++, cur_spec_cache++ ) { /* 2003.02.13: Was previously setting 'cur_sqlvar->sqlind = NULL;' here, ** but that's no longer valid because sqlind is allocated in ** reallocate_sqlda and not deallocated until delete_cursor. */ assert (cur_sqlvar->sqlind != NULL); cur_sqlvar->sqldata = NULL; /* Also restore the original sqlvar specification flags before attempting ** the conversion of this input row (they would have been reset if the ** Python object previously inbound to this XSQLVAR was implicitly ** converted from string -> whatever DB type the field really was). */ cur_sqlvar->sqltype = cur_spec_cache->sqltype; cur_sqlvar->sqllen = cur_spec_cache->sqllen; } /* 2003.03.15: Moved the supplied-vs-required param count check to AFTER ** the set-all-sqlvar-pointers null loop, so that the caller of this function ** can safely call free_XSQLVAR_dynamically_allocated_memory in ALL ** cases in which this function returns an error. */ if ( num_supplied_statement_params != num_required_statement_params ) { char raw_error_msg[] = "PyObject2XSQLDA: Incorrect number of input" " parameters. Expected %d; received %d."; char *processed_error_msg = kimem_main_malloc( strlen(raw_error_msg) + 60 ); /* There would be a buffer overflow here if the combined length of the ** string representations of num_required_statement_params and ** num_supplied_statement_params exceeded 64. ** Since XSQLDA->sqld is a short (max length 5 digits), the length of the ** incoming parameter sequence would have to be 59 digits long to trigger ** the buffer overflow. Since Python can't handle a sequence longer than ** 2147483647 elements, we're safe. */ sprintf( processed_error_msg, raw_error_msg, num_required_statement_params, num_supplied_statement_params ); raise_exception(ProgrammingError, processed_error_msg); kimem_main_free(processed_error_msg); return INPUT_ERROR; } for ( i = 0, cur_sqlvar = sqlda->sqlvar; i < num_required_statement_params; i++, cur_sqlvar++ ) { cur_param = PySequence_GetItem(params, i); if (cur_param == NULL) { return INPUT_ERROR; } conversion_status = PyObject2XSQLVAR(cursor, cur_sqlvar, cur_param); /* PySequence_GetItem returns a NEW reference, which must be released. */ Py_DECREF(cur_param); if (conversion_status != INPUT_OK) { return INPUT_ERROR; /* PyObject2XSQLVAR will have set exception. */ } } return INPUT_OK; } /* PyObject2XSQLDA */ #ifdef DETERMINE_FIELD_PRECISION #include "_kiconversion_field_precision.c" #endif /* DETERMINE_FIELD_PRECISION */ PyObject *XSQLDA2Description( XSQLDA *sqlda, CursorObject *cursor ) { /* Creates a Python DB API Cursor.description tuple from a database XSQLDA ** and a cursor object. */ const int var_count = sqlda->sqld; int var_index; PyObject *descs_for_all_fields; PyObject *desc_for_this_field; PyObject *type; XSQLVAR *sqlvar; short data_type; int display_size = -1; int internal_size; PyObject *precision; int scale; int field_can_be_null; descs_for_all_fields = PyTuple_New(var_count); if (descs_for_all_fields == NULL) { return PyErr_NoMemory(); } for (var_index = 0; var_index < var_count; var_index++) { sqlvar = sqlda->sqlvar + var_index; type = NULL; /* The length of desc_for_this_field is defined by the Python DB API. */ desc_for_this_field = PyTuple_New(7); if (desc_for_this_field == NULL) { Py_DECREF(descs_for_all_fields); return PyErr_NoMemory(); } data_type = XSQLVAR_SQLTYPE_IGNORING_NULL_FLAG(sqlvar); internal_size = (int) sqlvar->sqllen; scale = (int) sqlvar->sqlscale; #ifndef DETERMINE_FIELD_PRECISION precision = PyInt_FromLong(0); #else precision = determine_field_precision( ENTITY_TYPE_UNKNOWN, sqlvar->relname, sqlvar->relname_length, sqlvar->sqlname, sqlvar->sqlname_length, cursor ); if (precision == NULL) { /* Tried to determine the field's precision, but encountered an ** exception while doing so. determine_field_precision will have set ** the Python exception, so we just need to return NULL. */ Py_DECREF(descs_for_all_fields); Py_DECREF(desc_for_this_field); return NULL; } #endif /* DETERMINE_FIELD_PRECISION */ field_can_be_null = XSQLVAR_SQLTYPE_READ_NULL_FLAG(sqlvar); /* 2003.10.16: */ /* Make the description's type slot adapt to dynamic type translation ** instead of returning the same type regardless. */ if (data_type != SQL_ARRAY) { PyObject *translator_key = _get_cached_type_name_for_conventional_code( cursor->connection->dialect, data_type, sqlvar->sqlsubtype, sqlvar->sqlscale ); if (translator_key == NULL) { /* 2005.07.28 */ assert (PyErr_Occurred()); Py_DECREF(descs_for_all_fields); Py_DECREF(desc_for_this_field); Py_DECREF(precision); return NULL; } type = cursor_get_translator_output_type(cursor, translator_key); /* If there is no registered converter for $translator_key, $type will be ** NULL. That's fine; a default will be supplied below. */ } /* I've investigated the type-punning warning raised here by ** GCC -Wall -fstrict-aliasing and concluded that the behavior that causes ** it (casting a PyTypeObject* to a PyObject*) is unavoidable and not ** unsafe (see the definitions in Python's object.h). */ #define DEFAULT_TYPE_IS(default_type) \ if (type == NULL) { type = (PyObject *) &default_type; } switch (data_type) { case SQL_TEXT: case SQL_VARYING: DEFAULT_TYPE_IS(PyString_Type); display_size = (int) sqlvar->sqllen; break; case SQL_SHORT: DEFAULT_TYPE_IS(PyInt_Type); display_size = 6; break; case SQL_LONG: DEFAULT_TYPE_IS(PyInt_Type); display_size = 11; break; #ifdef INTERBASE6_OR_LATER case SQL_INT64: DEFAULT_TYPE_IS(PyLong_Type); display_size = 20; break; #endif /* INTERBASE6_OR_LATER */ case SQL_DOUBLE: case SQL_FLOAT: case SQL_D_FLOAT: DEFAULT_TYPE_IS(PyFloat_Type); display_size = 17; break; case SQL_BLOB: /* The next statement predates DSR's involvement with kinterbasdb. He ** doesn't regard it as such a hot idea, but has left it alone for the ** sake of backward compatibility. */ scale = sqlvar->sqlsubtype; DEFAULT_TYPE_IS(PyString_Type); display_size = 0; break; case SQL_TIMESTAMP: DEFAULT_TYPE_IS(PyTuple_Type); display_size = 22; break; #ifdef INTERBASE6_OR_LATER case SQL_TYPE_DATE: DEFAULT_TYPE_IS(PyTuple_Type); display_size = 10; break; case SQL_TYPE_TIME: DEFAULT_TYPE_IS(PyTuple_Type); display_size = 11; break; #endif /* INTERBASE6_OR_LATER */ case SQL_ARRAY: DEFAULT_TYPE_IS(PyList_Type); display_size = -1; /* Can't determine display size inexpensively. */ break; default: type = Py_None; /* Notice that type gets set to None, *not* NoneType. */ display_size = -1; /* Can't determine display size. */ } /* end switch on data type */ /* If there is an alias, place the alias, rather than the real column name, ** in the column name field of the descriptor tuple. Before this fix, the ** presence of an alias made no difference whatsoever in the descriptor ** setup, and was thus inaccessible to the client programmer. */ /* 2003.03.30: Switched to strncmp instead of strcmp because the sqlname ** fields are not null-terminated. */ if ( ( sqlvar->aliasname_length != sqlvar->sqlname_length ) || ( strncmp( sqlvar->sqlname, sqlvar->aliasname, sqlvar->sqlname_length ) != 0 ) ) { PyTuple_SET_ITEM(desc_for_this_field, 0, PyString_FromStringAndSize( sqlvar->aliasname, (int) sqlvar->aliasname_length ) ); } else { PyTuple_SET_ITEM(desc_for_this_field, 0, PyString_FromStringAndSize( sqlvar->sqlname, (int) sqlvar->sqlname_length ) ); } assert (type != NULL); Py_INCREF(type); /* desc_for_this_field[0] has already been set (above). */ PyTuple_SET_ITEM( desc_for_this_field, 1, type ); PyTuple_SET_ITEM( desc_for_this_field, 2, PyInt_FromLong( (long) display_size ) ); PyTuple_SET_ITEM( desc_for_this_field, 3, PyInt_FromLong( (long) internal_size ) ); PyTuple_SET_ITEM( desc_for_this_field, 4, precision ); PyTuple_SET_ITEM( desc_for_this_field, 5, PyInt_FromLong( (long) scale ) ); PyTuple_SET_ITEM( desc_for_this_field, 6, PyBool_FromLong( (long) field_can_be_null ) ); PyTuple_SET_ITEM( descs_for_all_fields, var_index, desc_for_this_field ); } return descs_for_all_fields; } /* XSQLDA2Description */ static PyObject *XSQLVAR2PyObject( CursorObject *cursor, XSQLVAR *sqlvar ) { PyObject *result = NULL; /* 2003.03.30: */ PyObject *converter = NULL; /* Crucial information about the data we're trying to convert: */ const short scale = sqlvar->sqlscale; const short data_type = XSQLVAR_SQLTYPE_IGNORING_NULL_FLAG(sqlvar); const short data_subtype = sqlvar->sqlsubtype; const unsigned short dialect = cursor->connection->dialect; /* Arrays are a special case--see kiconversion_array.c */ if (data_type != SQL_ARRAY) { converter = cursor_get_out_converter(cursor, data_type, data_subtype, scale, FALSE); /* cursor_get_out_converter returns NULL on error, borrowed reference to ** Py_None if there was no converter. */ if (converter == NULL) { return NULL; } } if ( XSQLVAR_IS_ALLOWED_TO_BE_NULL(sqlvar) && XSQLVAR_IS_NULL(sqlvar) ) { /* SQL NULL becomes Python None regardless of field type. */ Py_INCREF(Py_None); result = Py_None; /* Give converters a chance to act on this value: */ goto _XSQLVAR2PyObject_NATIVE_CONVERSION_FINISHED; } /* For documentation of these data_type cases, see the IB6 API Guide ** section entitled "SQL datatype macro constants". */ switch (data_type) { /* Character data: */ case SQL_TEXT: result = conv_out_char(sqlvar->sqldata, sqlvar->sqllen); break; case SQL_VARYING: result = conv_out_varchar(sqlvar->sqldata); break; /* Numeric data: */ case SQL_SHORT: case SQL_LONG: result = conv_out_short_long(sqlvar->sqldata, data_type, IS_FIXED_POINT__CONVENTIONAL(dialect, data_type, data_subtype, scale), scale ); break; #ifdef INTERBASE6_OR_LATER case SQL_INT64: result = conv_out_int64(sqlvar->sqldata, IS_FIXED_POINT__CONVENTIONAL(dialect, data_type, data_subtype, scale), scale ); break; #endif /* INTERBASE6_OR_LATER */ case SQL_FLOAT: result = conv_out_floating(*((float *) sqlvar->sqldata), dialect, scale); break; case SQL_DOUBLE: case SQL_D_FLOAT: result = conv_out_floating(*((double *) sqlvar->sqldata), dialect, scale); break; /* Date and time data: */ case SQL_TIMESTAMP: /* TIMESTAMP */ result = conv_out_timestamp(sqlvar->sqldata); break; #ifdef INTERBASE6_OR_LATER case SQL_TYPE_DATE: /* DATE */ result = conv_out_date(sqlvar->sqldata); break; case SQL_TYPE_TIME: /* TIME */ result = conv_out_time(sqlvar->sqldata); break; #endif /* INTERBASE6_OR_LATER */ /* Blob data (including blobs of subtype TEXT): */ case SQL_BLOB: result = conv_out_blob( (ISC_QUAD *)sqlvar->sqldata, cursor->status_vector, cursor->connection->db_handle, CON_GET_TRANS_HANDLE(cursor->connection) /* 2003.10.15a:OK */ ); break; /* Fix failure to raise specific error message regarding lack of ARRAY ** support (reported by Phil Harris). */ case SQL_ARRAY: /* Array support new on 2002.12.23. */ result = conv_out_array( cursor, (ISC_QUAD *) sqlvar->sqldata, cursor->status_vector, cursor->connection->db_handle, CON_GET_TRANS_HANDLE(cursor->connection), /* 2003.10.15a:OK */ sqlvar->relname, sqlvar->relname_length, sqlvar->sqlname, sqlvar->sqlname_length ); break; default: raise_exception( NotSupportedError, "Outgoing conversion of type not supported. " KIDB_REPORT " " KIDB_HOME_PAGE ); return NULL; } _XSQLVAR2PyObject_NATIVE_CONVERSION_FINISHED: /* Obviously mustn't invoke the converter if the original value was not ** loaded properly from the database. */ if (result != NULL) { /* Arrays are a special case that must not be handled here--see ** _kiconversion_array.c/conv_out_array_element. */ if (data_type != SQL_ARRAY) { assert (converter != NULL); /* Can't be NULL, but may be None. */ /* Replacing the PyObject pointer in result is *not* a refcount leak; see ** the comments in dynamically_type_convert_output_obj_if_necessary. */ result = dynamically_type_convert_output_obj_if_necessary( result, converter, data_type, data_subtype ); } } return result; } /* XSQLVAR2PyObject */ PyObject *XSQLDA2Tuple( CursorObject *cursor, XSQLDA *sqlda ) { int i, count = sqlda->sqld; PyObject *var; PyObject *record = PyTuple_New(count); if (record == NULL) { return PyErr_NoMemory(); } for (i = 0; i < count; i++) { var = XSQLVAR2PyObject( cursor, sqlda->sqlvar + i ); if (var == NULL) { /* XSQLVAR2PyObject will have set an exception; we can just return NULL. */ Py_DECREF(record); return NULL; } PyTuple_SET_ITEM(record, i, var); } return record; } /* XSQLDA2Tuple */