SQLRETURN libpqCreateSQLColumnsCustomizedResultSet()

in src/odbc/rsodbc/rslibpq.c [3478:3695]


SQLRETURN libpqCreateSQLColumnsCustomizedResultSet(
    RS_STMT_INFO *pStmt, short columnNum,
    const std::vector<SHOWCOLUMNSResult> &intermediateRS) {

    int intermediateRSLen = intermediateRS.size();
    int columnSize = 0, bufferLen = 0, charOctetLen = 0;
    short sqlType = 0, sqlDataType = 0, sqlDateSub = 0, precisions = 0,
          decimalDigit = 0, num_pre_radix = 0;

    std::string intStr = {0};
    std::string shortStr = {0};

    bool dateTimeCustomizePrecision = false;

    std::string rsType;

    PGresult *res = pStmt->pResultHead->pgResult;

    PQsetNumAttributes(res, columnNum);

    for (int i = 0; i < intermediateRSLen; i++) {
        // Reset the variable
        columnSize = 0;
        bufferLen = 0;
        charOctetLen = 0;
        sqlType = 0;
        sqlDataType = 0;
        sqlDateSub = 0;
        precisions = 0;
        decimalDigit = 0;
        num_pre_radix = 0;
        dateTimeCustomizePrecision = false;
        rsType.clear();

        // Retrieve customize precision for second fraction
        std::regex dateTimeRegex(
            "(time|timetz|timestamp|timestamptz)\\(\\d+\\).*");
        std::regex intervalRegex("interval.*.\\(\\d+\\)");
        std::string dataType = char2String(intermediateRS[i].data_type);
        if (std::regex_match(dataType, dateTimeRegex) ||
            std::regex_match(dataType, intervalRegex)) {
            std::string cleanedDataType =
                std::regex_replace(dataType, std::regex("\\(\\d+\\)"), "");
            trim(cleanedDataType);
            auto it = RsMetadataAPIHelper::typeInfoMap.find(cleanedDataType);
            if (it != RsMetadataAPIHelper::typeInfoMap.end()) {
                const auto &typeInfo = it->second;
                sqlType = typeInfo.sqlType;
                sqlDataType = typeInfo.sqlDataType;
                sqlDateSub = typeInfo.sqlDateSub;
                rsType = typeInfo.typeName;
            } else {
                rsType = cleanedDataType;
            }

            std::smatch match;
            if (std::regex_search(dataType, match,
                                  std::regex(".*\\(([0-9]+)\\).*"))) {
                precisions = std::stoi(match[1]);
                dateTimeCustomizePrecision = true;
            }
        } else {
            auto it = RsMetadataAPIHelper::typeInfoMap.find(
                (char *)intermediateRS[i].data_type);
            if (it != RsMetadataAPIHelper::typeInfoMap.end()) {
                const auto &typeInfo = it->second;
                sqlType = typeInfo.sqlType;
                sqlDataType = typeInfo.sqlDataType;
                sqlDateSub = typeInfo.sqlDateSub;
                rsType = typeInfo.typeName;
            } else {
                rsType = std::string(reinterpret_cast<const char *>(
                    intermediateRS[i].data_type));
            }
        }

        columnSize = RsMetadataAPIHelper::getColumnSize(
            rsType, intermediateRS[i].character_maximum_length,
            intermediateRS[i].numeric_precision);

        bufferLen = RsMetadataAPIHelper::getBufferLen(
            rsType, intermediateRS[i].character_maximum_length,
            intermediateRS[i].numeric_precision);

        decimalDigit = RsMetadataAPIHelper::getDecimalDigit(
            rsType, intermediateRS[i].numeric_scale, precisions,
            dateTimeCustomizePrecision);

        num_pre_radix = RsMetadataAPIHelper::getNumPrecRadix(rsType);

        charOctetLen = RsMetadataAPIHelper::getCharOctetLen(
            rsType, intermediateRS[i].character_maximum_length);

        // Catalog name
        PQsetvalue(res, i, kSQLColumns_TABLE_CAT,
                   (char *)intermediateRS[i].database_name,
                   intermediateRS[i].database_name_Len);

        // Schema name
        PQsetvalue(res, i, kSQLColumns_TABLE_SCHEM,
                   (char *)intermediateRS[i].schema_name,
                   intermediateRS[i].schema_name_Len);

        // Table name
        PQsetvalue(res, i, kSQLColumns_TABLE_NAME,
                   (char *)intermediateRS[i].table_name,
                   intermediateRS[i].table_name_Len);

        // Column name
        PQsetvalue(res, i, kSQLColumns_COLUMN_NAME,
                   (char *)intermediateRS[i].column_name,
                   intermediateRS[i].column_name_Len);

        // SQL type (concise data type)
        shortStr = std::to_string(sqlType);
        PQsetvalue(res, i, kSQLColumns_DATA_TYPE, shortStr.data(),
                   shortStr.size());

        // Redshift type name
        PQsetvalue(res, i, kSQLColumns_TYPE_NAME, (char *)rsType.c_str(),
                   rsType.size());

        // Column size
        if (columnSize == kNotApplicable) {
            PQsetvalue(res, i, kSQLColumns_COLUMN_SIZE, NULL, NULL_LEN);
        } else {
            intStr = std::to_string(columnSize);
            PQsetvalue(res, i, kSQLColumns_COLUMN_SIZE, intStr.data(),
                       intStr.size());
        }

        // Buffer length
        if (bufferLen == kNotApplicable) {
            PQsetvalue(res, i, kSQLColumns_BUFFER_LENGTH, NULL, NULL_LEN);
        } else {
            intStr = std::to_string(bufferLen);
            PQsetvalue(res, i, kSQLColumns_BUFFER_LENGTH, intStr.data(),
                       intStr.size());
        }

        // Decimal digits
        if (decimalDigit == kNotApplicable) {
            // Return NULL where DECIMAL_DIGITS is not applicable
            PQsetvalue(res, i, kSQLColumns_DECIMAL_DIGITS, NULL, NULL_LEN);
        } else {
            shortStr = std::to_string(decimalDigit);
            PQsetvalue(res, i, kSQLColumns_DECIMAL_DIGITS, shortStr.data(),
                       shortStr.size());
        }

        // Num prec radix
        if (num_pre_radix == kNotApplicable) {
            // Return NULL where NUM_PREC_RADIX is not applicable
            PQsetvalue(res, i, kSQLColumns_NUM_PREC_RADIX, NULL, NULL_LEN);
        } else {
            shortStr = std::to_string(num_pre_radix);
            PQsetvalue(res, i, kSQLColumns_NUM_PREC_RADIX, shortStr.data(),
                       shortStr.size());
        }

        // Nullable
        shortStr = std::to_string(RsMetadataAPIHelper::getNullable(
            char2String(intermediateRS[i].is_nullable)));
        PQsetvalue(res, i, kSQLColumns_NULLABLE, shortStr.data(),
                   shortStr.size());

        // Remarks
        PQsetvalue(res, i, kSQLColumns_REMARKS,
                   (char *)intermediateRS[i].remarks,
                   intermediateRS[i].remarks_Len);

        // Column default
        PQsetvalue(res, i, kSQLColumns_COLUMN_DEF,
                   (char *)intermediateRS[i].column_default,
                   intermediateRS[i].column_default_Len);

        // SQL Data type (non-concise data type)
        shortStr = std::to_string(sqlDataType);
        PQsetvalue(res, i, kSQLColumns_SQL_DATA_TYPE, shortStr.data(),
                   shortStr.size());

        // SQL Date data type subtype code
        if (sqlDateSub == kNotApplicable) {
            PQsetvalue(res, i, kSQLColumns_SQL_DATETIME_SUB, NULL, NULL_LEN);
        } else {
            shortStr = std::to_string(sqlDateSub);
            PQsetvalue(res, i, kSQLColumns_SQL_DATETIME_SUB, shortStr.data(),
                       shortStr.size());
        }

        // char octet length
        if (charOctetLen == kNotApplicable) {
            PQsetvalue(res, i, kSQLColumns_CHAR_OCTET_LENGTH, NULL, NULL_LEN);
        } else {
            intStr = std::to_string(charOctetLen);
            PQsetvalue(res, i, kSQLColumns_CHAR_OCTET_LENGTH, intStr.data(),
                       intStr.size());
        }

        // Ordinal position
        intStr = std::to_string(intermediateRS[i].ordinal_position);
        PQsetvalue(res, i, kSQLColumns_ORDINAL_POSITION, intStr.data(),
                   intStr.size());

        // Is nullable
        PQsetvalue(res, i, kSQLColumns_IS_NULLABLE,
                   (char *)intermediateRS[i].is_nullable,
                   intermediateRS[i].is_nullable_Len);
    }

    // Set the total row number
    pStmt->pResultHead->iNumberOfRowsInMem = intermediateRSLen;

    // Reset the current row number for fetching result
    pStmt->pResultHead->iCurRow = -1;

    return SQL_SUCCESS;
}