int pdo_sqlsrv_stmt_get_col_meta()

in source/pdo_sqlsrv/pdo_stmt.cpp [1082:1184]


int pdo_sqlsrv_stmt_get_col_meta( _Inout_ pdo_stmt_t *stmt, _In_ zend_long colno, _Inout_ zval *return_value)
{
    PDO_RESET_STMT_ERROR;
    PDO_VALIDATE_STMT;
    PDO_LOG_STMT_ENTRY;

    try {
        SQLSRV_ASSERT( stmt != NULL, "pdo_sqlsrv_stmt_get_col_meta: pdo_stmt object was null" );
        SQLSRV_ASSERT( Z_TYPE_P( return_value ) == IS_NULL, "Metadata already has value.  Must be NULL." );

        sqlsrv_stmt* driver_stmt = static_cast<sqlsrv_stmt*>( stmt->driver_data );
        SQLSRV_ASSERT( driver_stmt != NULL, "pdo_sqlsrv_stmt_get_col_meta: stmt->driver_data was null");

        // Based on PDOStatement::getColumnMeta API, this should return FALSE 
        // if the requested column does not exist in the result set, or if 
        // no result set exists. Thus, do not use SQLSRV_ASSERT, which causes 
        // the script to fail right away. Instead, log this warning if logging
        // is enabled
        if (colno < 0 || colno >= stmt->column_count || stmt->columns == NULL) {
            LOG( SEV_WARNING, "Invalid column number %1!d!", colno );
            return FAILURE;
        }

        // initialize the array to nothing, as PDO requires us to create it
        array_init(return_value);

        field_meta_data* core_meta_data;

        // metadata should have been saved earlier
        SQLSRV_ASSERT(colno < driver_stmt->current_meta_data.size(), "pdo_sqlsrv_stmt_get_col_meta: Metadata vector out of sync with column numbers");
        core_meta_data = driver_stmt->current_meta_data[colno];
        
        // add the following fields: flags, native_type, driver:decl_type, table
        if (driver_stmt->data_classification) {
            core_sqlsrv_sensitivity_metadata(driver_stmt);

            // initialize the column data classification array 
            zval data_classification;
            ZVAL_UNDEF(&data_classification);
            array_init(&data_classification);

            data_classification::fill_column_sensitivity_array(driver_stmt, (SQLSMALLINT)colno, &data_classification);

            add_assoc_zval(return_value, "flags", &data_classification);
        }
        else {
            add_assoc_long(return_value, "flags", 0);
        }

        // get the name of the data type
        char field_type_name[SQL_SERVER_IDENT_SIZE_MAX] = {'\0'};
        SQLSMALLINT out_buff_len;
        SQLLEN not_used;
        core::SQLColAttribute( driver_stmt, (SQLUSMALLINT) colno + 1, SQL_DESC_TYPE_NAME, field_type_name,
                               sizeof( field_type_name ), &out_buff_len, &not_used );
        add_assoc_string( return_value, "sqlsrv:decl_type", field_type_name );

        // get the PHP type of the column.  The types returned here mirror the types returned by debug_zval_dump when 
        // given a variable of the same type.  However, debug_zval_dump also gives the length of a string, and we only
        // say string, since the length is given in another field of the metadata array.
        long pdo_type = sql_type_to_pdo_type( core_meta_data->field_type );
        switch( pdo_type ) {
            case PDO_PARAM_STR:
            {
                //Declarations eliminate compiler warnings about string constant to char* conversions
                std::string key = "native_type";
                std::string str = "string";
                add_assoc_string( return_value, &key[0], &str[0] );
            }
                break;
            default:
                DIE( "pdo_sqlsrv_stmt_get_col_data: Unknown PDO type returned" );
                break;
        }

        // add the table name of the field.  All the tests so far show this to always be "", but we adhere to the PDO spec
        char table_name[SQL_SERVER_IDENT_SIZE_MAX] = {'\0'};
        SQLLEN field_type_num;
        core::SQLColAttribute( driver_stmt, (SQLUSMALLINT) colno + 1, SQL_DESC_TABLE_NAME, table_name, SQL_SERVER_IDENT_SIZE_MAX,
                               &out_buff_len, &field_type_num );
        add_assoc_string( return_value, "table", table_name );

#if PHP_VERSION_ID < 80100
        if( stmt->columns && stmt->columns[colno].param_type == PDO_PARAM_ZVAL ) {
            add_assoc_long( return_value, "pdo_type", pdo_type );
        }
#else
        if (stmt->columns) {
            add_assoc_long(return_value, "pdo_type", pdo_type);
        }
#endif
    }
    catch( core::CoreException& ) {
        zval_ptr_dtor(return_value);
        return FAILURE;
    }
    catch(...) {
        zval_ptr_dtor(return_value);
        DIE( "pdo_sqlsrv_stmt_get_col_meta: Unknown exception occurred while retrieving metadata." );
    }
    
    return SUCCESS;
}