void MADB_CleanBulkOperData(MADB_Stmt *Stmt, unsigned int ParamOffset)
{
  if (MADB_DOING_BULK_OPER(Stmt))
  {
    MADB_DescRecord *CRec;
    void            *DataPtr= NULL;
    MYSQL_BIND      *MaBind= NULL;
    int             i;

    for (i= ParamOffset; i < MADB_STMT_PARAM_COUNT(Stmt); ++i)
    {
      if (CRec= MADB_DescGetInternalRecord(Stmt->Apd, i, MADB_DESC_READ))
      {
        MaBind= &Stmt->params[i - ParamOffset];
        DataPtr= GetBindOffset(Stmt->Apd, CRec, CRec->DataPtr, 0, CRec->OctetLength);

        if (MaBind->buffer != DataPtr)
        {
          switch (CRec->ConciseType)
          {
          case DATETIME_TYPES:
            if (CanUseStructArrForDatetime(Stmt) == FALSE)
            {
              MADB_FREE(MaBind->buffer);
              break;
            }
            /* Otherwise falling through and do the same as for others */
          case SQL_C_WCHAR:
          case SQL_C_NUMERIC:
          {
            unsigned int i;
            for (i= 0; i < Stmt->Bulk.ArraySize; ++i)
            {
              MADB_FREE(((char**)MaBind->buffer)[i]);
            }
          }
          /* falling through */
          default:
            MADB_FREE(MaBind->buffer);
          }
        }

        MADB_FREE(MaBind->length);

        MADB_FREE(MaBind->u.indicator);
      }
    }
    Stmt->Bulk.ArraySize= 0;
    Stmt->Bulk.HasRowsToSkip= 0;
  }
}
/* {{{ MADB_DescSetIrdMetadata */
my_bool 
MADB_DescSetIrdMetadata(MADB_Stmt *Stmt, MYSQL_FIELD *Fields, unsigned int NumFields)
{
  SQLUINTEGER i;

  for (i=0; i < NumFields; i++)
  {
    if (MADB_SetIrdRecord(Stmt, MADB_DescGetInternalRecord(Stmt->Ird, i, MADB_DESC_WRITE), &Fields[i]))
    {
      return 1;
    }
  }
  return 0;
}
SQLRETURN MADB_DescGetRec(MADB_Desc *Desc,
    SQLSMALLINT RecNumber,
    SQLCHAR *Name,
    SQLSMALLINT BufferLength,
    SQLSMALLINT *StringLengthPtr,
    SQLSMALLINT *TypePtr,
    SQLSMALLINT *SubTypePtr,
    SQLLEN *LengthPtr,
    SQLSMALLINT *PrecisionPtr,
    SQLSMALLINT *ScalePtr,
    SQLSMALLINT *NullablePtr,
    BOOL isWChar)
{
  MADB_DescRecord *Record;
  SQLLEN Length;

  MADB_CLEAR_ERROR(&Desc->Error);

  if (!(Record= MADB_DescGetInternalRecord(Desc, RecNumber, MADB_DESC_READ)))
  {
    MADB_SetError(&Desc->Error, MADB_ERR_07009, NULL, 0);
    return Desc->Error.ReturnValue;
  }
  
  /* SQL_DESC_NAME */
  Length= MADB_SetString(isWChar ? CP_UTF8 : 0, Name, BufferLength, Record->BaseColumnName, SQL_NTS, &Desc->Error);
  if (StringLengthPtr)
    *StringLengthPtr= (SQLSMALLINT)Length;
  Record->Unnamed= SQL_NAMED;

  /* SQL_DESC_TYPE */
  *(SQLSMALLINT *)TypePtr= (SQLSMALLINT)Record->Type;

  /* SQL_DESC_DATETIME_INTERVAL_CODE */
  *(SQLSMALLINT *)SubTypePtr= Record->DateTimeIntervalCode;

  /* SQL_DESC_OCTET_LENGTH */
  *(SQLLEN *)LengthPtr= (SQLLEN)Record->OctetLength;

  /* SQL_DESC_PRECISION */
  *(SQLSMALLINT *)PrecisionPtr= (SQLSMALLINT)Record->Precision;

  /* SQL_DESC_SCALE */
  *(SQLSMALLINT *)ScalePtr= (SQLSMALLINT)Record->Scale;

  /* SQL_DESC_NULLABLE */
  *(SQLSMALLINT *)NullablePtr= (SQLSMALLINT)Record->Nullable;

  return SQL_SUCCESS;
}
MYSQL_RES *MADB_GetDefaultColumnValues(MADB_Stmt *Stmt, MYSQL_FIELD *fields)
{
  MADB_DynString DynStr;
  unsigned int i;
  MYSQL_RES *result= NULL;
  
  MADB_InitDynamicString(&DynStr, "SELECT COLUMN_NAME, COLUMN_DEFAULT FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_SCHEMA='", 512, 512);
  if (MADB_DynstrAppend(&DynStr, fields[0].db) ||
      MADB_DynstrAppend(&DynStr, "' AND TABLE_NAME='") ||
      MADB_DynstrAppend(&DynStr, fields[0].org_table) ||
      MADB_DynstrAppend(&DynStr, "' AND COLUMN_NAME IN ("))
    goto error;

  for (i=0; i < mysql_stmt_field_count(Stmt->stmt); i++)
  {
    MADB_DescRecord *Rec= MADB_DescGetInternalRecord(Stmt->Ard, i, MADB_DESC_READ);

    if (!Rec->inUse || MADB_ColumnIgnoredInAllRows(Stmt->Ard, Rec) == TRUE)
    {
      continue;
    }
    if (MADB_DynstrAppend(&DynStr, i > 0 ? ",'" : "'") ||
      MADB_DynstrAppend(&DynStr, fields[i].org_name) ||
      MADB_DynstrAppend(&DynStr, "'"))
    {
      goto error;
    }
  }
  if (MADB_DynstrAppend(&DynStr, ") AND COLUMN_DEFAULT IS NOT NULL"))
    goto error;

  LOCK_MARIADB(Stmt->Connection);
  if (mysql_query(Stmt->Connection->mariadb, DynStr.str))
    goto error;
  result= mysql_store_result(Stmt->Connection->mariadb);
  
error:
    UNLOCK_MARIADB(Stmt->Connection);
    MADB_DynstrFree(&DynStr);
    return result;
}
/* {{{ MADB_FixColumnDataTypes */
my_bool
MADB_FixColumnDataTypes(MADB_Stmt *Stmt, MADB_ShortTypeInfo *ColTypesArr)
{
  SQLUINTEGER      i;
  MADB_DescRecord *Record= NULL;

  if (ColTypesArr == NULL)
  {
    return 1;
  }
  for (i=0; i < Stmt->Ird->Header.Count; ++i)
  {
    if (ColTypesArr[i].SqlType != 0)
    {
      Record= MADB_DescGetInternalRecord(Stmt->Ird, i, MADB_DESC_READ);

      if (Record == NULL)
      {
        return 1;
      }
      Record->ConciseType= ColTypesArr[i].SqlType;
      Record->Nullable= ColTypesArr[i].Nullable;

      Record->Unsigned= ColTypesArr[i].Unsigned != 0 ? SQL_TRUE : SQL_FALSE;

      if (ColTypesArr[i].OctetLength > 0)
      {
        Record->OctetLength= ColTypesArr[i].OctetLength;
      }
      if (MADB_FixIrdRecord(Stmt, Record))
      {
        return 1;
      }
    }
  }

  /* If the stmt is re-executed, we should be able to fix columns again */
  Stmt->ColsTypeFixArr= ColTypesArr;
  return 0;
}
int MADB_FindNextDaeParam(MADB_Desc *Desc, int InitialParam, SQLSMALLINT RowNumber)
{
  int             i;
  MADB_DescRecord *Record;

  for (i= InitialParam > -1 ? InitialParam + 1 : 0; i < Desc->Header.Count; i++)
  {
    if ((Record= MADB_DescGetInternalRecord(Desc, i, MADB_DESC_READ)))
    {
      if (Record->OctetLengthPtr)
      {
        /* Stmt->DaeRowNumber is 1 based */
        SQLLEN *OctetLength = (SQLLEN *)GetBindOffset(Desc, Record, Record->OctetLengthPtr, RowNumber > 1 ? RowNumber - 1 : 0, sizeof(SQLLEN));
        if (PARAM_IS_DAE(OctetLength))
        {
          return i;
        }
      }
    }
  }

  return MADB_NOPARAM;
}
/* Assuming that bulk insert can't go with DAE(and that unlikely ever changes). And that it has been checked before this call,
and we can't have DAE here */
SQLRETURN MADB_ExecuteBulk(MADB_Stmt *Stmt, unsigned int ParamOffset)
{
  unsigned int  i, IndIdx= -1;
  unsigned long Dummy;

  for (i= ParamOffset; i < ParamOffset + MADB_STMT_PARAM_COUNT(Stmt); ++i)
  {
    MADB_DescRecord *CRec, *SqlRec;
    SQLLEN          *IndicatorPtr= NULL;
    SQLLEN          *OctetLengthPtr= NULL;
    void            *DataPtr= NULL;
    MYSQL_BIND      *MaBind= &Stmt->params[i - ParamOffset];
    SQLULEN         row, Start= Stmt->ArrayOffset;

    if ((CRec= MADB_DescGetInternalRecord(Stmt->Apd, i, MADB_DESC_READ)) &&
      (SqlRec= MADB_DescGetInternalRecord(Stmt->Ipd, i, MADB_DESC_READ)))
    {
      /* check if parameter was bound */
      if (!CRec->inUse)
      {
        return MADB_SetError(&Stmt->Error, MADB_ERR_07002, NULL, 0);
      }

      if (MADB_ConversionSupported(CRec, SqlRec) == FALSE)
      {
        return MADB_SetError(&Stmt->Error, MADB_ERR_07006, NULL, 0);
      }

      MaBind->length= NULL;
      IndicatorPtr=   (SQLLEN *)GetBindOffset(Stmt->Apd, CRec, CRec->IndicatorPtr, 0, sizeof(SQLLEN));
      OctetLengthPtr= (SQLLEN *)GetBindOffset(Stmt->Apd, CRec, CRec->OctetLengthPtr, 0, sizeof(SQLLEN));
      DataPtr=        GetBindOffset(Stmt->Apd, CRec, CRec->DataPtr, 0, CRec->OctetLength);

      /* If these are the same pointers, setting indicator to NULL to simplify things a bit */
      if (IndicatorPtr == OctetLengthPtr)
      {
        IndicatorPtr= NULL;
      }
      /* Well, specs kinda say, that both values and lenghts arrays should be set(in instruction to param array operations)
         But there is no error/sqlstate for the case if any of those pointers is not set. Thus we assume that is possible */
      if (DataPtr == NULL)
      {
        /* Special case - DataPtr is not set, we treat it as all values are NULL. Setting indicators and moving on next param */
        RETURN_ERROR_OR_CONTINUE(MADB_InitIndicatorArray(Stmt, MaBind, MADB_MapIndicatorValue(SQL_NULL_DATA)));
        continue;
      }

      /* Sets Stmt->Bulk.HasRowsToSkip if needed, since it traverses and checks status array anyway */
      RETURN_ERROR_OR_CONTINUE(MADB_InitBulkOperBuffers(Stmt, CRec, DataPtr, OctetLengthPtr, IndicatorPtr, SqlRec->ConciseType, MaBind));

      if (MaBind->u.indicator != NULL && IndIdx == (unsigned int)-1)
      {
        IndIdx= i - ParamOffset;
      }

      /* Doing it on last parameter - just to do do this once, and to use already allocated indicator array.
         Little stupid optimization. But it's actually even a bit simpler this way */
      if (i == ParamOffset + MADB_STMT_PARAM_COUNT(Stmt) - 1 && Stmt->Bulk.HasRowsToSkip)
      {
        if (IndIdx == (unsigned int)-1)
        {
          IndIdx= 0;
        }

        for (row= Start; row < Start + Stmt->Apd->Header.ArraySize; ++row)
        {
          if (Stmt->Apd->Header.ArrayStatusPtr[row] == SQL_PARAM_IGNORE)
          {
            MADB_SetIndicatorValue(Stmt, &Stmt->params[IndIdx], (unsigned int)row, SQL_PARAM_IGNORE);
          }
        }       
      }

      if (MADB_AppBufferCanBeUsed(CRec->ConciseType, SqlRec->ConciseType))
      {
        /* Everything has been done for such column already */
        continue;
      }

      /* We either have skipped rows or need to convert parameter values/convert array */
      for (row= Start; row < Start + Stmt->Apd->Header.ArraySize; ++row, DataPtr= (char*)DataPtr + CRec->OctetLength)
      {
        void *Buffer= (char*)MaBind->buffer + row*MaBind->buffer_length;
        void **BufferPtr= (void**)Buffer; /* For the case when Buffer points to the pointer already */

        if (Stmt->Apd->Header.ArrayStatusPtr != NULL && Stmt->Apd->Header.ArrayStatusPtr[row] == SQL_PARAM_IGNORE)
        {
          continue;
        }
        if (MaBind->u.indicator && MaBind->u.indicator[row] > STMT_INDICATOR_NONE)
        {
          continue;
        }

        switch (CRec->ConciseType)
        {
        case SQL_C_CHAR:
          if (SqlRec->ConciseType != SQL_BIT)
          {
            break;
          }
        case DATETIME_TYPES:
          if (CanUseStructArrForDatetime(Stmt))
          {
            BufferPtr= &Buffer;
          }
        }

        /* Need &Dummy here as a length ptr, since NULL is not good here.
           It would make MADB_ConvertC2Sql to use MaBind->buffer_length by default */
        if (!SQL_SUCCEEDED(MADB_ConvertC2Sql(Stmt, CRec, DataPtr, MaBind->length != NULL ? MaBind->length[row] : 0,
          SqlRec, MaBind, BufferPtr, MaBind->length != NULL ? MaBind->length + row : &Dummy)))
        {
          /* Perhaps it's better to move to Clean function */
          CRec->InternalBuffer= NULL;
          return Stmt->Error.ReturnValue;
        }
        CRec->InternalBuffer= NULL;
      }
    }
  }

  return MADB_DoExecute(Stmt, FALSE);
}
/* {{{ MADB_DescSetField */
SQLRETURN MADB_DescSetField(SQLHDESC DescriptorHandle,
                            SQLSMALLINT RecNumber,
                            SQLSMALLINT FieldIdentifier,
                            SQLPOINTER ValuePtr,
                            SQLINTEGER BufferLength,
                            my_bool isWChar)
{
  MADB_Desc *Desc= (MADB_Desc *)DescriptorHandle;
  MADB_DescRecord *DescRecord= NULL;
  SQLRETURN ret;
  SQL_UNNAMED;
  ret= MADB_DeskCheckFldId(Desc, FieldIdentifier, MADB_DESC_WRITE);

  /* Application may set IPD's field SQL_DESC_UNNAMED to SQL_UNNAMED only */
  if (FieldIdentifier == SQL_DESC_UNNAMED && (SQLSMALLINT)ValuePtr == SQL_NAMED)
  {
    MADB_SetError(&Desc->Error, MADB_ERR_HY092, NULL, 0);
    ret= Desc->Error.ReturnValue;
  }

  if (!SQL_SUCCEEDED(ret))
    return ret;

  MADB_CLEAR_ERROR(&Desc->Error);
  switch (FieldIdentifier) {
  case SQL_DESC_ARRAY_SIZE:
    Desc->Header.ArraySize= (SQLUINTEGER)ValuePtr;
    return SQL_SUCCESS;
  case SQL_DESC_ARRAY_STATUS_PTR:
    Desc->Header.ArrayStatusPtr= (SQLUSMALLINT *)ValuePtr;
    return SQL_SUCCESS;
  case SQL_DESC_BIND_OFFSET_PTR:
    Desc->Header.BindOffsetPtr= (SQLUINTEGER *)ValuePtr;
    return SQL_SUCCESS;
  case SQL_DESC_BIND_TYPE:
    Desc->Header.BindType= (SQLUINTEGER)ValuePtr;
    return SQL_SUCCESS;
  case SQL_DESC_COUNT:
    Desc->Header.Count= (SQLINTEGER)ValuePtr;
    return SQL_SUCCESS;
  case SQL_DESC_ROWS_PROCESSED_PTR:
    Desc->Header.RowsProcessedPtr= (SQLULEN *)ValuePtr;
    return SQL_SUCCESS;
  }

  if (RecNumber > 0)
  {
    if (!(DescRecord= MADB_DescGetInternalRecord(Desc, RecNumber - 1, MADB_DESC_WRITE)))
      return SQL_ERROR;

    switch (FieldIdentifier) {
    case SQL_DESC_CONCISE_TYPE:
      DescRecord->ConciseType= (SQLSMALLINT)ValuePtr;
      DescRecord->Type= MADB_GetTypeFromConciseType(DescRecord->ConciseType);
      break;
    case SQL_DESC_DATA_PTR:
      DescRecord->DataPtr= ValuePtr;
      break;
    case SQL_DESC_DATETIME_INTERVAL_CODE:
      DescRecord->DateTimeIntervalCode= (SQLSMALLINT)ValuePtr;
      break;
    case SQL_DESC_DATETIME_INTERVAL_PRECISION:
      DescRecord->DateTimeIntervalPrecision= (SQLINTEGER)ValuePtr;
      break;
    case SQL_DESC_FIXED_PREC_SCALE:
      DescRecord->FixedPrecScale= (SQLSMALLINT)ValuePtr;
      break;
    case SQL_DESC_INDICATOR_PTR:
      DescRecord->IndicatorPtr= (SQLINTEGER *)ValuePtr;
      break;
    case SQL_DESC_LENGTH:
      DescRecord->DescLength= (SQLINTEGER)ValuePtr;
      break;
    case SQL_DESC_NUM_PREC_RADIX:
      DescRecord->NumPrecRadix= (SQLINTEGER)ValuePtr;
      break;
    case SQL_DESC_OCTET_LENGTH:
      DescRecord->OctetLength= (SQLINTEGER)ValuePtr;
      break;
    case SQL_DESC_OCTET_LENGTH_PTR:
      DescRecord->OctetLengthPtr= (SQLINTEGER *)ValuePtr;
      break;
    case SQL_DESC_PARAMETER_TYPE:
      DescRecord->ParameterType= (SQLSMALLINT)ValuePtr;
      break;
    case SQL_DESC_PRECISION:
      DescRecord->Precision= (SQLSMALLINT)ValuePtr;
      break;
    case SQL_DESC_SCALE:
      DescRecord->Scale= (SQLSMALLINT)ValuePtr;
      break;
    case SQL_DESC_TYPE:
      DescRecord->Type= (SQLSMALLINT)ValuePtr;
      DescRecord->ConciseType= DescRecord->Type;
      break;
    }
    /* bug41018 (ma_desc.c):
     We need to unbind in case parameter doesn't set a buffer or header field */
    switch (FieldIdentifier)
    {
    case SQL_DESC_DATA_PTR:
    case SQL_DESC_OCTET_LENGTH_PTR:
    case SQL_DESC_INDICATOR_PTR:
      break;
    default:
      if (Desc->DescType== MADB_DESC_ARD && DescRecord && DescRecord->DataPtr)
        DescRecord->DataPtr= NULL;
      break;
    }
  
    if (DescRecord)
      DescRecord->inUse= 1;
  }
  return ret;
}
/* {{{ MADB_DescGetField */
SQLRETURN MADB_DescGetField(SQLHDESC DescriptorHandle,
                            SQLSMALLINT RecNumber,
                            SQLSMALLINT FieldIdentifier,
                            SQLPOINTER ValuePtr,
                            SQLINTEGER BufferLength,
                            SQLINTEGER *StringLengthPtr,
                            my_bool isWChar)
{
  MADB_Desc *Desc= (MADB_Desc *)DescriptorHandle;
  MADB_DescRecord *DescRecord= NULL;
  SQLRETURN ret;
  size_t Length;

  /* Bookmark */
  if (RecNumber < 1)
  {
    /* todo */

  }

  ret= MADB_DeskCheckFldId(Desc, FieldIdentifier, MADB_DESC_READ);
  if (!SQL_SUCCEEDED(ret))
    return ret;

  MADB_CLEAR_ERROR(&Desc->Error);

  if (RecNumber)
    if (!(DescRecord= MADB_DescGetInternalRecord(Desc, RecNumber - 1, MADB_DESC_READ)))
      return SQL_ERROR;

  switch (FieldIdentifier) {
  case SQL_DESC_ALLOC_TYPE:
    *((SQLINTEGER *)ValuePtr)= Desc->Header.AllocType;
    break;
  case SQL_DESC_ARRAY_SIZE:
    *((SQLULEN *)ValuePtr)= Desc->Header.ArraySize;
    break;
  case SQL_DESC_ARRAY_STATUS_PTR:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)Desc->Header.ArrayStatusPtr;
    break;
  case SQL_DESC_BIND_OFFSET_PTR:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)Desc->Header.BindOffsetPtr;
    break;
  case SQL_DESC_BIND_TYPE:
    *((SQLINTEGER *)ValuePtr)= Desc->Header.BindType;
    break;
  case SQL_DESC_COUNT:
    *(SQLINTEGER *)ValuePtr= Desc->Header.Count;
    break;
  case SQL_DESC_ROWS_PROCESSED_PTR:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)Desc->Header.RowsProcessedPtr;
    break;
  case SQL_DESC_AUTO_UNIQUE_VALUE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->AutoUniqueValue;
    break;
  case SQL_DESC_BASE_COLUMN_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->BaseColumnName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    break;
  case SQL_DESC_BASE_TABLE_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->BaseTableName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    break;
  case SQL_DESC_CASE_SENSITIVE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->CaseSensitive;
    break;
  case SQL_DESC_CATALOG_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->BaseCatalogName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    break;
  case SQL_DESC_CONCISE_TYPE:
    *((SQLSMALLINT *)ValuePtr)= DescRecord->ConciseType;
    break;
  case SQL_DESC_DATA_PTR:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->DataPtr;
    break;
  case SQL_DESC_DATETIME_INTERVAL_CODE:
    *((SQLSMALLINT *)ValuePtr)= DescRecord->DateTimeIntervalCode;
    break;
  case SQL_DESC_DATETIME_INTERVAL_PRECISION:
    *((SQLINTEGER *)ValuePtr)= DescRecord->DateTimeIntervalPrecision;
    break;
  case SQL_DESC_FIXED_PREC_SCALE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->FixedPrecScale;
    break;
  case SQL_DESC_INDICATOR_PTR:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->IndicatorPtr;
    break;
  case SQL_DESC_LENGTH:
   *((SQLINTEGER *)ValuePtr)= DescRecord->DescLength;
    break;
  case SQL_DESC_LITERAL_PREFIX:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->LiteralPrefix;
    break;
  case SQL_DESC_LITERAL_SUFFIX:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->LiteralSuffix;
    break;
  case SQL_DESC_LOCAL_TYPE_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->LocalTypeName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    break;
  case SQL_DESC_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->BaseColumnName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    DescRecord->Unnamed= SQL_NAMED;
    break;
  case SQL_DESC_NULLABLE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Nullable;
    break;
  case SQL_DESC_NUM_PREC_RADIX:
    *((SQLINTEGER *)ValuePtr)= DescRecord->NumPrecRadix;
    break;
  case SQL_DESC_OCTET_LENGTH:
    *((SQLINTEGER *)ValuePtr)= DescRecord->OctetLength;
    break;
  case SQL_DESC_OCTET_LENGTH_PTR:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->OctetLengthPtr;
    break;
  case SQL_DESC_PARAMETER_TYPE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->ParameterType;
    break;
  case SQL_DESC_PRECISION:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Precision;
    break;
#if (ODBCVER >= 0x0350)
  case SQL_DESC_ROWVER:
    *((SQLPOINTER *)ValuePtr)= (SQLPOINTER)DescRecord->RowVer;
    break;
#endif
  case SQL_DESC_SCALE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Scale;
    break;
  case SQL_DESC_SCHEMA_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->SchemaName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    break;
  case SQL_DESC_SEARCHABLE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Searchable;
    break;
  case SQL_DESC_TABLE_NAME:
    Length= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->TableName, SQL_NTS, &Desc->Error);
    if (StringLengthPtr)
      *StringLengthPtr= Length;
    break;
  case SQL_DESC_TYPE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Type;
    break;
  case SQL_DESC_TYPE_NAME:
    *StringLengthPtr= MADB_SetString(isWChar ? CP_UTF8 : 0, ValuePtr, BufferLength, DescRecord->TypeName, SQL_NTS, &Desc->Error);
     break;
  case SQL_DESC_UNSIGNED:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Unsigned;
    break;
  case SQL_DESC_UPDATABLE:
    *((SQLINTEGER *)ValuePtr)= DescRecord->Updateable;
    break;
  }
  return ret;
}