ngx_int_t
ngx_http_drizzle_output_row(ngx_http_request_t *r, uint64_t row)
{
    u_char                              *pos, *last;
    ngx_http_upstream_t                 *u = r->upstream;
    size_t                               size;

    ngx_http_upstream_drizzle_peer_data_t   *dp = u->peer.data;

    size = sizeof(uint8_t);

    pos = ngx_http_drizzle_request_mem(r, dp, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

    *last++ = (row != 0);

    if (row == 0) {
        dp->seen_stream_end = 1;
    }

    return ngx_http_drizzle_submit_mem(r, dp, size, row == 0 ? 1 : 0 /* last_buf */);
}
ngx_int_t
ngx_http_drizzle_output_result_header(ngx_http_request_t *r,
        drizzle_result_st *res)
{
    u_char                          *pos, *last;
    ngx_int_t                        rc;
    ngx_http_upstream_t             *u = r->upstream;
    const char                      *errstr;
    size_t                           size;
    uint16_t                         errstr_len;
    uint16_t                         col_count;
    unsigned                         last_buf;

    ngx_http_upstream_drizzle_peer_data_t   *dp = u->peer.data;

    errstr = drizzle_result_error(res);

    errstr_len = (uint16_t) strlen(errstr);

    col_count = drizzle_result_column_count(res);

    size = sizeof(uint8_t)      /* endian type */
         + sizeof(uint32_t)     /* format version */
         + sizeof(uint8_t)      /* result type */

         + sizeof(uint16_t)     /* standard error code */
         + sizeof(uint16_t)     /* driver-specific error code */

         + sizeof(uint16_t)     /* driver-specific errstr len */
         + errstr_len           /* driver-specific errstr data */
         + sizeof(uint64_t)     /* rows affected */
         + sizeof(uint64_t)     /* insert id */
         + sizeof(uint16_t)     /* column count */
         ;

    pos = ngx_http_drizzle_request_mem(r, dp, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

#if NGX_HAVE_LITTLE_ENDIAN
    *last++ = 0;
#else /* big endian */
    *last++ = 1;
#endif

    /* RDS format version */

    *(uint32_t *) last = (uint32_t) resty_dbd_stream_version;
    last += sizeof(uint32_t);

    /* result type fixed to 0 */
    *last++ = 0;

    /* standard error code
     * FIXME: define the standard error code set and map
     * libdrizzle's to it. */
    *(uint16_t *) last = drizzle_result_error_code(res);
    last += sizeof(uint16_t);

     /* driver-specific error code */
    *(uint16_t *) last = drizzle_result_error_code(res);
    last += sizeof(uint16_t);

    /* driver-specific errstr len */
    *(uint16_t *) last = errstr_len;
    last += sizeof(uint16_t);

    /* driver-specific errstr data */
    if (errstr_len) {
        last = ngx_copy(last, (u_char *) errstr, errstr_len);
    }

    /* affected rows */
    *(uint64_t *) last = drizzle_result_affected_rows(res);
    last += sizeof(uint64_t);

    /* insert id */
    *(uint64_t *) last = drizzle_result_insert_id(res);
    last += sizeof(uint64_t);

    /* column count */
    *(uint16_t *) last = col_count;
    last += sizeof(uint16_t);

    if ((size_t) (last - pos) != size) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
               "drizzle: FATAL: output result header buffer error");
        return NGX_ERROR;
    }

    if (col_count == 0) {
        /* we suppress row terminator here when there's no columns */
        dp->seen_stream_end = 1;

        if (r == r->main) {
            last_buf = 1;
        } else {
            last_buf = 0;
        }

        rc = ngx_http_drizzle_submit_mem(r, dp, size, last_buf);

        if (rc != NGX_OK) {
            return NGX_ERROR;
        }

        ngx_http_upstream_drizzle_done(r, u, dp, NGX_OK);
        return NGX_DONE;
    }

    return ngx_http_drizzle_submit_mem(r, dp, size, 0 /* last_buf */);
}
ngx_int_t
ngx_http_drizzle_output_field(ngx_http_request_t *r, size_t offset,
        size_t len, size_t total, drizzle_field_t field)
{
    u_char                              *pos, *last;
    ngx_http_upstream_t                 *u = r->upstream;
    size_t                               size = 0;

    ngx_http_upstream_drizzle_peer_data_t   *dp = u->peer.data;

    if (offset == 0) {

        if (len == 0 && total != 0) {
            return NGX_DONE;
        }

        size = sizeof(uint32_t);     /* field total length */
    }

    /* (more) field data */
    size += (uint32_t) len;

    /* request memory */

    pos = ngx_http_drizzle_request_mem(r, dp, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

    /* fill in the buffer */

    if (offset == 0) {
        /* field total length */
        if (field == NULL) {
            *(uint32_t *) last = (uint32_t) -1;
        } else {
            *(uint32_t *) last = (uint32_t) total;
        }

        last += sizeof(uint32_t);
    }

    /* field data */
    if (len) {
        last = ngx_copy(last, field, (uint32_t) len);
    }

    if ((size_t) (last - pos) != size) {
        dd("offset %d, len %d, size %d", (int) offset,
                (int) len, (int) size);

        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
               "drizzle: FATAL: output field buffer error");

        return NGX_ERROR;
    }

    return ngx_http_drizzle_submit_mem(r, dp, size, 0 /* last_buf */);
}
ngx_int_t
ngx_http_drizzle_output_col(ngx_http_request_t *r, drizzle_column_st *col)
{
    u_char                              *pos, *last;
    ngx_http_upstream_t                 *u = r->upstream;
    drizzle_column_type_t                col_type = 0;
    uint16_t                             std_col_type = 0;
    const char                          *col_name = NULL;
    uint16_t                             col_name_len = 0;
    size_t                               size;

    ngx_http_upstream_drizzle_peer_data_t   *dp = u->peer.data;

    if (col == NULL) {
        return NGX_ERROR;
    }

    col_type = drizzle_column_type(col);
    col_name = drizzle_column_name(col);
    col_name_len = (uint16_t) strlen(col_name);

    size = sizeof(uint16_t)     /* std col type */
         + sizeof(uint16_t)     /* driver-specific col type */
         + sizeof(uint16_t)     /* col name str len */
         + col_name_len         /* col name str len */
         ;

    pos = ngx_http_drizzle_request_mem(r, dp, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

    /* std column type */

    std_col_type = (uint16_t) ngx_http_drizzle_std_col_type(col_type);

#if 0
    dd("std col type for %s: %d, %d (%d, %d, %d)",
            col_name, std_col_type, rds_col_type_blob,
            rds_rough_col_type_str,
            rds_rough_col_type_str << 14,
            (uint16_t) (19 | (rds_rough_col_type_str << 14))
            );
#endif

    *(uint16_t *) last = std_col_type;
    last += sizeof(uint16_t);

    /* drizzle column type */
    *(uint16_t *) last = col_type;
    last += sizeof(uint16_t);

    /* column name string length */
    *(uint16_t *) last = col_name_len;
    last += sizeof(uint16_t);

    /* column name string data */
    last = ngx_copy(last, col_name, col_name_len);

    if ((size_t) (last - pos) != size) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
               "drizzle: FATAL: output column buffer error");
        return NGX_ERROR;
    }

    return ngx_http_drizzle_submit_mem(r, dp, size, 0 /* last_buf */);
}
ngx_int_t
ngx_http_drizzle_output_result_header(ngx_http_request_t *r,
    drizzle_result_st *res)
{
    u_char                          *pos, *last;
    ngx_int_t                        rc;
    ngx_http_upstream_t             *u = r->upstream;
    const char                      *errstr;
    size_t                           size;
    uint16_t                         errstr_len;
    uint16_t                         col_count;
    uint16_t                         errcode;

    ngx_http_upstream_drizzle_peer_data_t   *dp = u->peer.data;

    errcode = drizzle_result_error_code(res);

    if (dp->enable_charset && ! dp->has_set_names) {
        if (errcode != 0) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "drizzle: FATAL: failed to set names 'utf8' "
                          "(error %d)", (int) errcode);
            return NGX_ERROR;
        }

        if (dp->drizzle_con && dp->drizzle_res.con) {
            dd("before drizzle result free");
            dd("%p vs. %p", dp->drizzle_res.con, dp->drizzle_con);

            drizzle_result_free(&dp->drizzle_res);

            dd("after drizzle result free");
        }

        /* ngx_http_upstream_drizzle_done(r, u, dp, NGX_OK); */
        dd("returning DONE when set names");
        return NGX_DONE;
    }

    errstr = drizzle_result_error(res);

    errstr_len = (uint16_t) ngx_strlen(errstr);

    col_count = drizzle_result_column_count(res);

    size = sizeof(uint8_t)        /* endian type */
           + sizeof(uint32_t)     /* format version */
           + sizeof(uint8_t)      /* result type */

           + sizeof(uint16_t)     /* standard error code */
           + sizeof(uint16_t)     /* driver-specific error code */

           + sizeof(uint16_t)     /* driver-specific errstr len */
           + errstr_len           /* driver-specific errstr data */
           + sizeof(uint64_t)     /* rows affected */
           + sizeof(uint64_t)     /* insert id */
           + sizeof(uint16_t);    /* column count */

    pos = ngx_http_drizzle_request_mem(r, dp, size);
    if (pos == NULL) {
        return NGX_ERROR;
    }

    last = pos;

#if NGX_HAVE_LITTLE_ENDIAN
    *last++ = 0;
#else /* big endian */
    *last++ = 1;
#endif

    /* RDS format version */

    *(uint32_t *) last = (uint32_t) resty_dbd_stream_version;
    last += sizeof(uint32_t);

    /* result type fixed to 0 */
    *last++ = 0;

    /* standard error code
     * FIXME: define the standard error code set and map
     * libdrizzle's to it. */
    *(uint16_t *) last = errcode;
    last += sizeof(uint16_t);

     /* driver-specific error code */
    *(uint16_t *) last = drizzle_result_error_code(res);
    last += sizeof(uint16_t);

    /* driver-specific errstr len */
    *(uint16_t *) last = errstr_len;
    last += sizeof(uint16_t);

    /* driver-specific errstr data */
    if (errstr_len) {
        last = ngx_copy(last, (u_char *) errstr, errstr_len);
    }

    /* affected rows */
    *(uint64_t *) last = drizzle_result_affected_rows(res);
    last += sizeof(uint64_t);

    /* insert id */
    *(uint64_t *) last = drizzle_result_insert_id(res);
    last += sizeof(uint64_t);

    /* column count */
    *(uint16_t *) last = col_count;
    last += sizeof(uint16_t);

    if ((size_t) (last - pos) != size) {
        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                      "drizzle: FATAL: output result header buffer error");
        return NGX_ERROR;
    }

    if (col_count == 0) {
        dd("Col count is ZERO");

        /* we suppress row terminator here when there's no columns */
        dp->seen_stream_end = 1;

        rc = ngx_http_drizzle_submit_mem(r, dp, size);

        if (rc != NGX_OK) {
            return NGX_ERROR;
        }

        dd("about to be done...");
        ngx_http_upstream_drizzle_done(r, u, dp, NGX_DONE);
        dd("i am returning DONE");

        return NGX_DONE;
    }

    return ngx_http_drizzle_submit_mem(r, dp, size);
}