SQLRETURN DESC::set_field()

in driver/desc.cc [739:925]


SQLRETURN DESC::set_field(SQLSMALLINT recnum, SQLSMALLINT fldid,
                      SQLPOINTER val, SQLINTEGER buflen)
{
  desc_field *fld = getfield(fldid);
  void *dest_struct;
  void *dest;

  error.clear();

  /* check for invalid IRD modification */
  if (is_ird())
  {
    switch (fldid)
    {
      case SQL_DESC_ARRAY_STATUS_PTR:
      case SQL_DESC_ROWS_PROCESSED_PTR:
        break;
      default:
      return set_error("HY016",
                      "Cannot modify an implementation row descriptor",
                      MYERR_S1016);
    }
  }

  if ((fld == NULL) ||
      /* header permissions check */
      (fld->loc == DESC_HDR &&
         ((ref_type == DESC_APP && (~fld->perms & P_WA)) ||
          (ref_type == DESC_IMP && (~fld->perms & P_WI)))))
  {
    return set_error("HY091",
                     "Invalid descriptor field identifier",
                     MYERR_S1091);
  }
  else if (fld->loc == DESC_REC)
  {
    int perms= 0; /* needed perms to access */

    if (ref_type == DESC_APP)
      perms= P_WA;
    else if (ref_type == DESC_IMP)
      perms= P_WI;

    if (desc_type == DESC_PARAM)
      perms= P_PAR(perms);
    else if (desc_type == DESC_ROW)
      perms= P_ROW(perms);

    if ((~fld->perms & perms) == perms)
      return set_error("HY091",
                       "Invalid descriptor field identifier",
                       MYERR_S1091);
  }

  /* get the dest struct */
  if (fld->loc == DESC_HDR)
    dest_struct= this;
  else
  {
    if (recnum < 1 && stmt->stmt_options.bookmarks == SQL_UB_OFF)
      return set_error("07009",
                       "Invalid descriptor index",
                       MYERR_07009);
    else
      dest_struct= desc_get_rec(this, recnum - 1, TRUE);
  }

  dest= ((char *)dest_struct) + fld->offset;

  /* some applications and even MSDN examples don't give a correct constant */
  if (buflen == 0)
    buflen= fld->data_type;

  /* TODO checks when strings? */
  if ((fld->data_type == SQL_IS_POINTER && buflen != SQL_IS_POINTER) ||
      (fld->data_type != SQL_IS_POINTER && buflen == SQL_IS_POINTER))
    return set_error("HY015",
                     "Invalid parameter type",
                     MYERR_S1015);

  /* per-field checks/functionality */
  switch (fldid)
  {
  case SQL_DESC_COUNT:
    /* we just force the descriptor record count to expand */
    (void)desc_get_rec(this, (int)((size_t)val - 1), TRUE);
    break;
  case SQL_DESC_NAME:
    {
      // dest_struct already points to the correct DESCREC*
      DESCREC *name_rec = (DESCREC*)dest_struct;
      // Add name as parameter data and zero terminating character
      name_rec->par.add_param_data((char*)val, (unsigned long)strlen((char*)val) + 1);
      // Get a pointer to allocated copy of the name
      val = name_rec->par.val();
    }
    break;
    /* We don't support named parameters, values stay as initialized */
    //return set_desc_error(desc, "01S01",
    //                      "Option value changed",
    //                      MYERR_01S02);
  case SQL_DESC_UNNAMED:
    if ((size_t)val == SQL_NAMED)
      return set_error("HY092",
                       "Invalid attribute/option identifier",
                       MYERR_S1092);
  }

  /* We have to unbind the value if not setting a buffer */
  switch (fldid)
  {
  case SQL_DESC_DATA_PTR:
  case SQL_DESC_OCTET_LENGTH_PTR:
  case SQL_DESC_INDICATOR_PTR:
    break;
  default:
    if (fld->loc == DESC_REC)
    {
      DESCREC *rec= (DESCREC *) dest_struct;
      rec->data_ptr= NULL;
    }
  }

  apply_desc_val(dest, fld->data_type, val, buflen);

  /* post-set responsibilities */
  /*http://msdn.microsoft.com/en-us/library/ms710963%28v=vs.85%29.aspx
    "ParameterType Argument" sectiosn - basically IPD has to be heres as well with same rules
    C and SQL types match. Thus we can use same function for calculation of type and dti code.
   */
  if ((is_ard() || is_apd() || is_ipd()) && fld->loc == DESC_REC)
  {
    DESCREC *rec= (DESCREC *) dest_struct;
    switch (fldid)
    {
    case SQL_DESC_TYPE:
      rec->concise_type= rec->type;
      rec->datetime_interval_code= 0;
      break;
    case SQL_DESC_CONCISE_TYPE:
      rec->type= get_type_from_concise_type(rec->concise_type);
      rec->datetime_interval_code=
        get_dticode_from_concise_type(rec->concise_type);
      break;
    case SQL_DESC_DATETIME_INTERVAL_CODE: /* TODO validation for this value? */
      /* SQL_DESC_TYPE has to have already been set */
      if (rec->type == SQL_DATETIME)
        rec->concise_type=
          get_concise_type_from_datetime_code(rec->datetime_interval_code);
      else
        rec->concise_type=
          get_concise_type_from_interval_code(rec->datetime_interval_code);
      break;
    }

    switch (fldid)
    {
    case SQL_DESC_TYPE:
    case SQL_DESC_CONCISE_TYPE:
      /* setup type specific defaults (TODO others besides SQL_C_NUMERIC)? */
      if (is_ard() && rec->type == SQL_C_NUMERIC)
      {
        rec->precision= 38;
        rec->scale= 0;
      }
    }
  }

  /*
    Set "real_param_done" for parameters if all fields needed to bind
    a parameter are set.
  */
  if (is_apd() && val != NULL && fld->loc == DESC_REC)
  {
    DESCREC *rec= (DESCREC *) dest_struct;
    switch (fldid)
    {
    case SQL_DESC_DATA_PTR:
    case SQL_DESC_OCTET_LENGTH_PTR:
    case SQL_DESC_INDICATOR_PTR:
      rec->par.real_param_done= TRUE;
      break;
    }
  }

  return SQL_SUCCESS;
}