ClickHouse-Encoder
view release on metacpan or search on metacpan
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 )