SQLRETURN EsSQLGetDescFieldW()

in driver/handles.c [1565:1829]


SQLRETURN EsSQLGetDescFieldW(
	SQLHDESC        DescriptorHandle,
	SQLSMALLINT     RecNumber,
	SQLSMALLINT     FieldIdentifier,
	_Out_writes_opt_(_Inexpressible_(BufferLength))
	SQLPOINTER      ValuePtr,
	SQLINTEGER      BufferLength, /* byte count, also for wchar's */
	SQLINTEGER      *StringLengthPtr)
{
	esodbc_desc_st *desc = DSCH(DescriptorHandle);
	esodbc_state_et state;
	wstr_st wstr;
	SQLSMALLINT word;
	SQLINTEGER intgr;
	esodbc_rec_st *rec;

	if (! check_access(desc, FieldIdentifier, O_RDONLY)) {
		int llev;
#if 0
		/*
		 * Actually, the spec ask to return success, but just set nothing: ???
		 * "When an application calls SQLGetDescField to retrieve the value of
		 * a field that is undefined for a particular descriptor type, the
		 * function returns SQL_SUCCESS but the value returned for the field
		 * is undefined."
		 */
		llev = LOG_LEVEL_ERR;
		state = SQL_STATE_HY091;
#else /* 0 */
		llev = LOG_LEVEL_WARN;
		state = SQL_STATE_01000;
#endif /* 0 */
		LOGH(desc, llev, 0, "field (%d) access check failed: not defined for "
			"desciptor (type: %d).", FieldIdentifier, desc->type);
		RET_HDIAG(desc, state,
			"field type not defined for descriptor", 0);
	}

	state = check_buff(FieldIdentifier, ValuePtr, BufferLength, TRUE);
	if (state != SQL_STATE_00000) {
		ERRH(desc, "buffer/~ length check failed (%d).", state);
		RET_HDIAGS(desc, state);
	}

	/* header fields */
	switch (FieldIdentifier) {
		case SQL_DESC_ALLOC_TYPE:
			*(SQLSMALLINT *)ValuePtr = desc->alloc_type;
			DBGH(desc, "returning: desc alloc type: %hu.",
				*(SQLSMALLINT *)ValuePtr);
			return SQL_SUCCESS;

		case SQL_DESC_ARRAY_SIZE:
			*(SQLULEN *)ValuePtr = desc->array_size;
			DBGH(desc, "returning: desc array size: %llu.",
				(uint64_t)*(SQLULEN *)ValuePtr);
			return SQL_SUCCESS;

		case SQL_DESC_ARRAY_STATUS_PTR:
			*(SQLUSMALLINT **)ValuePtr =
				desc->array_status_ptr;
			DBGH(desc, "returning: status array ptr: 0x%p.",
				(SQLUSMALLINT *)ValuePtr);
			return SQL_SUCCESS;

		case SQL_DESC_BIND_OFFSET_PTR:
			*(SQLLEN **)ValuePtr = desc->bind_offset_ptr;
			DBGH(desc, "returning binding offset ptr: 0x%p.",
				(SQLLEN *)ValuePtr);
			return SQL_SUCCESS;

		case SQL_DESC_BIND_TYPE:
			*(SQLUINTEGER *)ValuePtr = desc->bind_type;
			DBGH(desc, "returning bind type: %lu.", *(SQLUINTEGER *)ValuePtr);
			return SQL_SUCCESS;

		case SQL_DESC_COUNT:
			*(SQLSMALLINT *)ValuePtr = desc->count;
			DBGH(desc, "returning count: %hd.", *(SQLSMALLINT *)ValuePtr);
			return SQL_SUCCESS;

		case SQL_DESC_ROWS_PROCESSED_PTR:
			*(SQLULEN **)ValuePtr = desc->rows_processed_ptr;
			DBGH(desc, "returning desc rows processed ptr: 0x%p.", ValuePtr);
			return SQL_SUCCESS;
	}

	/*
	 * The field is a record field -> get the record to apply the field to.
	 */
	if (RecNumber < 0) { /* TODO: need to check also if AxD, as per spec?? */
		ERRH(desc, "negative record number provided (%d) with record field "
			"(%d).", RecNumber, FieldIdentifier);
		RET_HDIAG(desc, SQL_STATE_07009,
			"Negative record number provided with record field", 0);
	} else if (RecNumber == 0) {
		ERRH(desc, "unsupported record number 0."); /* TODO: bookmarks? */
		RET_HDIAG(desc, SQL_STATE_07009,
			"Unsupported record number 0", 0);
	} else {
		/*
		 * "When an application calls SQLGetDescField to retrieve the value of
		 * a field that is defined for a particular descriptor type but that
		 * has no default value and has not been set yet, the function returns
		 * SQL_SUCCESS but the value returned for the field is undefined."
		 */
		rec = get_record(desc, RecNumber, FALSE);
		if (! rec) {
			WARNH(desc, "record #%d not yet set; returning defaults.",
				RecNumber);
			get_rec_default(FieldIdentifier, BufferLength, ValuePtr);
			return SQL_SUCCESS;
		}
		DBGH(desc, "getting field %d of record #%d @ 0x%p.", FieldIdentifier,
			RecNumber, rec);
	}

	ASSERT_IXD_HAS_ES_TYPE(rec);

	/*INDENT-OFF*/
	/* record fields */
	switch (FieldIdentifier) {
		/* <SQLPOINTER> */
		case SQL_DESC_DATA_PTR:
			*(SQLPOINTER *)ValuePtr = rec->data_ptr;
			DBGH(desc, "returning data pointer 0x%p.", rec->data_ptr);
			break;

		/* <SQLWCHAR *> */
		do {
		case SQL_DESC_BASE_COLUMN_NAME: wstr = rec->base_column_name; break;
		case SQL_DESC_BASE_TABLE_NAME: wstr = rec->base_table_name; break;
		case SQL_DESC_CATALOG_NAME: wstr = rec->catalog_name; break;
		case SQL_DESC_LABEL: wstr = rec->label; break;
		case SQL_DESC_NAME: wstr = rec->name; break;
		case SQL_DESC_SCHEMA_NAME: wstr = rec->schema_name; break;
		case SQL_DESC_TABLE_NAME: wstr = rec->table_name; break;
		case SQL_DESC_LITERAL_PREFIX:
			wstr = rec->es_type->literal_prefix;
			break;
		case SQL_DESC_LITERAL_SUFFIX:
			wstr = rec->es_type->literal_suffix;
			break;
		case SQL_DESC_LOCAL_TYPE_NAME:
			wstr = rec->es_type->local_type_name;
			break;
		case SQL_DESC_TYPE_NAME:
			wstr = rec->es_type->type_name;
			break;
		} while (0);
			if (! StringLengthPtr) {
				RET_HDIAGS(desc, SQL_STATE_HY009);
			} else {
				*StringLengthPtr = (SQLINTEGER)wstr.cnt;
			}
			if (ValuePtr) {
				memcpy(ValuePtr, wstr.str, *StringLengthPtr);
			}
			DBGH(desc, "returning SQLWCHAR record field %d: `" LWPDL "`.",
					FieldIdentifier, LWSTR(&wstr));
			break;

		/* <SQLLEN *> */
		case SQL_DESC_INDICATOR_PTR:
			*(SQLLEN **)ValuePtr = rec->indicator_ptr;
			DBGH(desc, "returning indicator pointer: 0x%p.",
					rec->indicator_ptr);
			break;
		case SQL_DESC_OCTET_LENGTH_PTR:
			*(SQLLEN **)ValuePtr = rec->octet_length_ptr;
			DBGH(desc, "returning octet length pointer 0x%p.",
					rec->octet_length_ptr);
			break;

		/* <SQLLEN> */
		case SQL_DESC_DISPLAY_SIZE:
			*(SQLLEN *)ValuePtr = rec->es_type->display_size;
			DBGH(desc, "returning display size: %d.",
					rec->es_type->display_size);
			break;
		case SQL_DESC_OCTET_LENGTH:
			*(SQLLEN *)ValuePtr = rec->octet_length;
			DBGH(desc, "returning octet length: %d.", rec->octet_length);
			break;

		/* <SQLULEN> */
		case SQL_DESC_LENGTH:
			*(SQLULEN *)ValuePtr = rec->length;
			DBGH(desc, "returning length: %llu.", (uint64_t)rec->length);
			break;

		/* <SQLSMALLINT> */
		do {
		case SQL_DESC_CONCISE_TYPE: word = rec->concise_type; break;
		case SQL_DESC_TYPE: word = rec->type; break;
		case SQL_DESC_DATETIME_INTERVAL_CODE:
			word = rec->datetime_interval_code; break;

		case SQL_DESC_PARAMETER_TYPE: word = rec->parameter_type; break;
		case SQL_DESC_ROWVER: word = rec->rowver; break;
		case SQL_DESC_UNNAMED: word = rec->unnamed; break;
		case SQL_DESC_PRECISION:
			if (rec->desc->type == DESC_TYPE_IRD) {
				word = (SQLSMALLINT)rec->es_type->column_size;
			} else {
				word = rec->precision;
			}
			break;
		case SQL_DESC_SCALE:
			if (rec->desc->type == DESC_TYPE_IRD) {
				word = rec->es_type->maximum_scale;
			} else {
				word = rec->scale;
			}
			break;
		case SQL_DESC_FIXED_PREC_SCALE:
			word = rec->es_type->fixed_prec_scale;
			break;
		case SQL_DESC_NULLABLE: word = rec->es_type->nullable; break;
		case SQL_DESC_SEARCHABLE: word = rec->es_type->searchable; break;
		case SQL_DESC_UNSIGNED: word = rec->es_type->unsigned_attribute; break;
		case SQL_DESC_UPDATABLE: word = rec->updatable; break;
		} while (0);
			*(SQLSMALLINT *)ValuePtr = word;
			DBGH(desc, "returning record field %d as %d.", FieldIdentifier,
					word);
			break;

		/* <SQLINTEGER> */
		do {
		case SQL_DESC_DATETIME_INTERVAL_PRECISION:
			if (DESC_TYPE_IS_IMPLEMENTATION(rec->desc->type)) {
				/* not used with ES (so far), as no interval types are sup. */
				intgr = rec->es_type->interval_precision;
			} else {
				intgr = rec->datetime_interval_precision;
			}
			break;
		case SQL_DESC_NUM_PREC_RADIX:
			if DESC_TYPE_IS_IMPLEMENTATION(rec->desc->type) {
				intgr = rec->es_type->num_prec_radix;
			} else {
				intgr = rec->num_prec_radix;
			}
			break;
		case SQL_DESC_AUTO_UNIQUE_VALUE:
			intgr = rec->es_type->auto_unique_value;
			break;
		case SQL_DESC_CASE_SENSITIVE:
			intgr = rec->es_type->case_sensitive;
			break;
		} while (0);
			*(SQLINTEGER *)ValuePtr = intgr;
			DBGH(desc, "returning record field %d as %d.", FieldIdentifier,
					intgr);
			break;

		default:
			ERRH(desc, "unknown FieldIdentifier: %d.", FieldIdentifier);
			RET_HDIAGS(desc, SQL_STATE_HY091);
	}
	/*INDENT-ON*/

	return SQL_SUCCESS;
}