RETCODE SQL_API OPENSEARCHAPI_DescribeCol()

in sql-odbc/src/sqlodbc/results.c [96:311]


RETCODE SQL_API OPENSEARCHAPI_DescribeCol(HSTMT hstmt, SQLUSMALLINT icol,
                                  SQLCHAR *szColName, SQLSMALLINT cbColNameMax,
                                  SQLSMALLINT *pcbColName,
                                  SQLSMALLINT *pfSqlType, SQLULEN *pcbColDef,
                                  SQLSMALLINT *pibScale,
                                  SQLSMALLINT *pfNullable) {
    CSTR func = "OPENSEARCHAPI_DescribeCol";

    /* gets all the information about a specific column */
    StatementClass *stmt = (StatementClass *)hstmt;
    ConnectionClass *conn;
    IRDFields *irdflds;
    QResultClass *res = NULL;
    char *col_name = NULL;
    OID fieldtype = 0;
    SQLLEN column_size = 0;
    int unknown_sizes;
    SQLINTEGER decimal_digits = 0;
    ConnInfo *ci;
    FIELD_INFO *fi;
    char buf[255];
    int len = 0;
    RETCODE result = SQL_SUCCESS;

    MYLOG(OPENSEARCH_TRACE, "entering.%d..\n", icol);

    if (!stmt) {
        SC_log_error(func, NULL_STRING, NULL);
        return SQL_INVALID_HANDLE;
    }

    conn = SC_get_conn(stmt);
    ci = &(conn->connInfo);
    unknown_sizes = DEFAULT_UNKNOWNSIZES;

    SC_clear_error(stmt);

#ifdef __APPLE__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wkeyword-macro"
#endif  // __APPLE__
#define return DONT_CALL_RETURN_FROM_HERE ? ? ?
#ifdef __APPLE__
#pragma clang diagnostic pop
#endif  // __APPLE__
    irdflds = SC_get_IRDF(stmt);
    if (0 == icol) /* bookmark column */
    {
        SQLSMALLINT fType = stmt->options.use_bookmarks == SQL_UB_VARIABLE
                                ? SQL_BINARY
                                : SQL_INTEGER;

        MYLOG(OPENSEARCH_ALL, "answering bookmark info\n");
        if (szColName && cbColNameMax > 0)
            *szColName = '\0';
        if (pcbColName)
            *pcbColName = 0;
        if (pfSqlType)
            *pfSqlType = fType;
        if (pcbColDef)
            *pcbColDef = 10;
        if (pibScale)
            *pibScale = 0;
        if (pfNullable)
            *pfNullable = SQL_NO_NULLS;
        result = SQL_SUCCESS;
        goto cleanup;
    }

    /*
     * Dont check for bookmark column. This is the responsibility of the
     * driver manager.
     */

    icol--; /* use zero based column numbers */

    fi = NULL;
    if (icol < irdflds->nfields && irdflds->fi)
        fi = irdflds->fi[icol];

    if (!FI_is_applicable(fi)) {
        fi = NULL;

        res = SC_get_Curres(stmt);
        if (icol >= QR_NumPublicResultCols(res)) {
            SC_set_error(stmt, STMT_INVALID_COLUMN_NUMBER_ERROR,
                         "Invalid column number in DescribeCol.", func);
            SPRINTF_FIXED(buf, "Col#=%d, #Cols=%d,%d keys=%d", icol,
                          QR_NumResultCols(res), QR_NumPublicResultCols(res),
                          res->num_key_fields);
            SC_log_error(func, buf, stmt);
            result = SQL_ERROR;
            goto cleanup;
        }
        if (icol < irdflds->nfields && irdflds->fi)
            fi = irdflds->fi[icol];
    }
    res = SC_get_Curres(stmt);
#ifdef SUPPRESS_LONGEST_ON_CURSORS
    if (UNKNOWNS_AS_LONGEST == unknown_sizes) {
        if (QR_once_reached_eof(res))
            unknown_sizes = UNKNOWNS_AS_LONGEST;
        else
            unknown_sizes = UNKNOWNS_AS_MAX;
    }
#endif /* SUPPRESS_LONGEST_ON_CURSORS */
    /* handle constants */
    if (res && -2 == QR_get_fieldsize(res, icol))
        unknown_sizes = UNKNOWNS_AS_LONGEST;

    if (FI_is_applicable(fi)) {
        fieldtype = getEffectiveOid(conn, fi);
        if (NAME_IS_VALID(fi->column_alias))
            col_name = GET_NAME(fi->column_alias);
        else
            col_name = GET_NAME(fi->column_name);
        if (USE_FI(fi, unknown_sizes)) {
            column_size = fi->column_size;
            decimal_digits = fi->decimal_digits;
        } else {
            column_size = opensearchtype_column_size(stmt, fieldtype, icol,
                                                     unknown_sizes);
            decimal_digits =
                opensearchtype_decimal_digits(stmt, fieldtype, icol);
        }

        MYLOG(OPENSEARCH_DEBUG,
              "PARSE: fieldtype=%u, col_name='%s', column_size=" FORMAT_LEN
              "\n",
              fieldtype, NULL_IF_NULL(col_name), column_size);
    } else {
        col_name = QR_get_fieldname(res, icol);
        fieldtype = QR_get_field_type(res, icol);

        column_size =
            opensearchtype_column_size(stmt, fieldtype, icol, unknown_sizes);
        decimal_digits = opensearchtype_decimal_digits(stmt, fieldtype, icol);
    }

    MYLOG(OPENSEARCH_DEBUG, "col %d fieldname = '%s'\n", icol, NULL_IF_NULL(col_name));
    MYLOG(OPENSEARCH_DEBUG, "col %d fieldtype = %d\n", icol, fieldtype);
    MYLOG(OPENSEARCH_DEBUG, "col %d column_size = " FORMAT_LEN "\n", icol, column_size);

    result = SQL_SUCCESS;

    /*
     * COLUMN NAME
     */
    len = col_name ? (int)strlen(col_name) : 0;

    if (pcbColName)
        *pcbColName = (SQLSMALLINT)len;

    if (szColName && cbColNameMax > 0) {
        if (NULL != col_name)
            strncpy_null((char *)szColName, col_name, cbColNameMax);
        else
            szColName[0] = '\0';

        if (len >= cbColNameMax) {
            result = SQL_SUCCESS_WITH_INFO;
            SC_set_error(stmt, STMT_TRUNCATED,
                         "The buffer was too small for the colName.", func);
        }
    }

    /*
     * CONCISE(SQL) TYPE
     */
    if (pfSqlType) {
        *pfSqlType = opensearchtype_to_concise_type(stmt, fieldtype, icol,
                                                    unknown_sizes);

        MYLOG(OPENSEARCH_DEBUG, "col %d *pfSqlType = %d\n", icol, *pfSqlType);
    }

    /*
     * COLUMN SIZE(PRECISION in 2.x)
     */
    if (pcbColDef) {
        if (column_size < 0)
            column_size = 0; /* "I dont know" */

        *pcbColDef = column_size;

        MYLOG(OPENSEARCH_DEBUG, "Col: col %d  *pcbColDef = " FORMAT_ULEN "\n", icol,
              *pcbColDef);
    }

    /*
     * DECIMAL DIGITS(SCALE in 2.x)
     */
    if (pibScale) {
        if (decimal_digits < 0)
            decimal_digits = 0;

        *pibScale = (SQLSMALLINT)decimal_digits;
        MYLOG(OPENSEARCH_DEBUG, "col %d  *pibScale = %d\n", icol, *pibScale);
    }

    /*
     * NULLABILITY
     */
    if (pfNullable) {
        if (SC_has_outer_join(stmt))
            *pfNullable = TRUE;
        else
            *pfNullable = fi ? fi->nullable : opensearchtype_nullable(conn, fieldtype);

        MYLOG(OPENSEARCH_DEBUG, "col %d  *pfNullable = %d\n", icol, *pfNullable);
    }

cleanup:
#undef return
    return result;
}