void fetch_fields_common()

in source/sqlsrv/stmt.cpp [1836:1913]


void fetch_fields_common( _Inout_ ss_sqlsrv_stmt* stmt, _In_ zend_long fetch_type, _Out_ zval& fields, _In_ bool allow_empty_field_names )
{
	void* field_value = NULL;
	sqlsrv_phptype sqlsrv_php_type;
	sqlsrv_php_type.typeinfo.type = SQLSRV_PHPTYPE_INVALID;
	SQLSRV_PHPTYPE sqlsrv_php_type_out = SQLSRV_PHPTYPE_INVALID;

	// make sure that the fetch type is legal
	CHECK_CUSTOM_ERROR((fetch_type < MIN_SQLSRV_FETCH || fetch_type > MAX_SQLSRV_FETCH), stmt, SS_SQLSRV_ERROR_INVALID_FETCH_TYPE, stmt->func()) {
		throw ss::SSException();
	}

    // get the numer of columns in the result set and its metadata if not exists
    SQLSMALLINT num_cols = get_resultset_meta_data(stmt);

	// if this is the first fetch in a new result set, then get the field names and
	// store them off for successive fetches.
    if ((fetch_type & SQLSRV_FETCH_ASSOC) && stmt->fetch_field_names == NULL) {

        SQLLEN field_name_len = 0;
        sqlsrv_malloc_auto_ptr<sqlsrv_fetch_field_name> field_names;
        field_names = static_cast<sqlsrv_fetch_field_name*>(sqlsrv_malloc(num_cols * sizeof(sqlsrv_fetch_field_name)));
        for (int i = 0; i < num_cols; ++i) {
            // The meta data field name is already null-terminated, and the field name len is correct.
            field_name_len = stmt->current_meta_data[i]->field_name_len;
            field_names[i].name = static_cast<char*>(sqlsrv_malloc(field_name_len, sizeof(char), 1));
            memcpy_s((void*)field_names[i].name, (field_name_len * sizeof(char)), (void*)stmt->current_meta_data[i]->field_name, field_name_len);
            field_names[i].name[field_name_len] = '\0';     // null terminate the field name after the memcpy
            field_names[i].len = field_name_len;            // field_name_len should not need to include the null char
        }

        stmt->fetch_field_names = field_names;
        stmt->fetch_fields_count = num_cols;
        field_names.transferred();
    }

    int zr = SUCCESS;
    array_init(&fields);

    for( int i = 0; i < num_cols; ++i ) {
        SQLLEN field_len = -1;

        core_sqlsrv_get_field( stmt, i, sqlsrv_php_type, true /*prefer string*/,
                                    field_value, &field_len, false /*cache_field*/, &sqlsrv_php_type_out );

        zval field;
        ZVAL_UNDEF( &field );
        convert_to_zval( stmt, sqlsrv_php_type_out, field_value, field_len, field );
        sqlsrv_free( field_value );
        if( fetch_type & SQLSRV_FETCH_NUMERIC ) {

            zr = add_next_index_zval( &fields, &field );
            CHECK_ZEND_ERROR( zr, stmt, SQLSRV_ERROR_ZEND_HASH ) {
                throw ss::SSException();
            }
        }

        if( fetch_type & SQLSRV_FETCH_ASSOC ) {

            CHECK_CUSTOM_WARNING_AS_ERROR(( stmt->fetch_field_names[i].len == 0 && !allow_empty_field_names ), stmt,
                                            SS_SQLSRV_WARNING_FIELD_NAME_EMPTY) {
                throw ss::SSException();
            }

            if( stmt->fetch_field_names[i].len > 0 || allow_empty_field_names ) {

                add_assoc_zval(&fields, stmt->fetch_field_names[i].name, &field);
            }
        }
        //only addref when the fetch_type is BOTH because this is the only case when fields(hashtable)
        //has 2 elements pointing to field. Do not addref if the type is NUMERIC or ASSOC because
        //fields now only has 1 element pointing to field and we want the ref count to be only 1
        if (fetch_type == SQLSRV_FETCH_BOTH) {
            Z_TRY_ADDREF(field);
        }
    } //for loop

}