ClickHouse-Encoder

 view release on metacpan or  search on metacpan

Encoder.xs  view on Meta::CPAN

    for (c = 0; c < ncols; c++) {
        const char *name; STRLEN name_len;
        const char *tstr; STRLEN tlen;
        dec_lenpfx_string(aTHX_ &p, end, &name, &name_len);
        dec_lenpfx_string(aTHX_ &p, end, &tstr, &tlen);
        /* parse_type uses heap-slot SAVEDESTRUCTOR_X for cleanup on
         * croak; on success the slot is disarmed. We're in the XSUB's
         * implicit save scope, so a croak from any nested decode
         * unwinds the type back through this cleanup. */
        TypeInfo *t = parse_type(aTHX_ tstr, tlen);

        int keep = 1;
        if (keep_set && !hv_exists(keep_set, name, name_len))
            keep = 0;

        SV *values;
        if (keep) {
            values = decode_column(aTHX_ &p, end, t, (SSize_t)nrows);
        } else {
            /* Decode then discard - we still must consume the wire
             * bytes to keep the cursor aligned for the next column.
             * The AV is freed immediately so peak memory is one
             * column's values, not the full block's. */
            SV *tmp = decode_column(aTHX_ &p, end, t, (SSize_t)nrows);
            SvREFCNT_dec(tmp);
            AV *placeholder = newAV();
            if (nrows > 0) {
                av_extend(placeholder, nrows - 1);
                SSize_t r;
                for (r = 0; r < (SSize_t)nrows; r++)
                    av_store(placeholder, r, newSV(0));
            }
            values = newRV_noinc((SV *)placeholder);
        }
        /* Free this column's TypeInfo eagerly to avoid piling them up
         * on the save stack for wide blocks. */
        free_typeinfo(aTHX_ t);

        HV *col_hv = newHV();
        (void)hv_stores(col_hv, "name",   newSVpvn(name, name_len));
        (void)hv_stores(col_hv, "type",   newSVpvn(tstr, tlen));
        (void)hv_stores(col_hv, "values", values);
        if (!keep) (void)hv_stores(col_hv, "skipped", newSViv(1));
        av_store(cols, c, newRV_noinc((SV *)col_hv));
    }

    HV *result = newHV();
    (void)hv_stores(result, "ncols",    newSVuv(ncols));
    (void)hv_stores(result, "nrows",    newSVuv(nrows));
    /* Transfer ownership out of the mortal: bump refcount, then the
     * mortal-stack cleanup at scope exit drops one back, leaving the
     * net refcount at 1 (owned by `result`). */
    (void)hv_stores(result, "columns",
                    newRV_inc((SV *)cols));
    (void)hv_stores(result, "consumed", newSVuv((UV)(p - start)));
    RETVAL = newRV_noinc((SV *)result);
}
OUTPUT: RETVAL

# Row-oriented decoder: same wire walk as decode_block, but values are
# distributed into row-major arrayrefs as each column is decoded, then
# the per-column AV is freed. Peak memory holds one column's values
# plus all row AVs (vs decode_rows-via-Perl which holds both
# representations + does the transpose in Perl).
SV *
decode_block_rows(class, bytes, ...)
    SV *class
    SV *bytes
CODE:
{
    PERL_UNUSED_VAR(class);
    UV start_offset = 0;
    if (items >= 3) {
        IV signed_off = SvIV(ST(2));
        if (signed_off < 0)
            croak("decode_block_rows: offset must be non-negative "
                  "(got %" IVdf ")", signed_off);
        start_offset = (UV)signed_off;
    }
    const unsigned char *start, *p, *end;
    UV ncols, nrows;
    decode_block_prologue(aTHX_ bytes, start_offset, "decode_block_rows",
                          &start, &p, &end, &ncols, &nrows);

    /* Mortalize so a mid-loop croak unwinds and reclaims these
     * (and, via the row RVs they hold, all populated row AVs).
     * SvREFCNT_inc-via-newRV_inc transfers them to the result HV
     * on the success path. */
    AV *names = (AV *)sv_2mortal((SV *)newAV());
    AV *types = (AV *)sv_2mortal((SV *)newAV());
    AV *rows  = (AV *)sv_2mortal((SV *)newAV());
    if (ncols > 0) { av_extend(names, ncols - 1); av_extend(types, ncols - 1); }
    if (nrows > 0) av_extend(rows, nrows - 1);

    /* Pre-create row AVs - we'll fill column c into row_av[c] as we
     * decode each column. Stash AV pointers for fast access. */
    AV **row_avs = NULL;
    if (nrows > 0) {
        Newx(row_avs, nrows, AV *);
        SAVEFREEPV(row_avs);
        UV r;
        for (r = 0; r < nrows; r++) {
            AV *row_av = newAV();
            if (ncols > 0) av_extend(row_av, ncols - 1);
            row_avs[r] = row_av;
            av_store(rows, r, newRV_noinc((SV *)row_av));
        }
    }

    UV c;
    for (c = 0; c < ncols; c++) {
        const char *name; STRLEN name_len;
        const char *tstr; STRLEN tlen;
        dec_lenpfx_string(aTHX_ &p, end, &name, &name_len);
        dec_lenpfx_string(aTHX_ &p, end, &tstr, &tlen);
        TypeInfo *t = parse_type(aTHX_ tstr, tlen);
        SV *col_rv = decode_column(aTHX_ &p, end, t, (SSize_t)nrows);
        free_typeinfo(aTHX_ t);

        AV *col_av = (AV *)SvRV(col_rv);
        UV r;



( run in 0.632 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )