Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 5 additions & 14 deletions mysql-test/suite/villagesql/std_data/bad_type_funcs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,23 +34,14 @@ void f1_impl(std::string_view from, vsql::CustomResult out) {
}

// Generic TO_STRING function
bool f2_impl(vsql::Span<const unsigned char> buf,
vsql::Span<char> to, size_t *to_length) {
(void)buf;

if (to.size() < 4) {
return true;
}

strcpy(to.data(), "val");
*to_length = 3;
return false;
void f2_impl(vsql::CustomArg in, vsql::StringResult out) {
(void)in;
out.set("val");
}

// Generic COMPARE function
int f3_impl(vsql::Span<const unsigned char> a,
vsql::Span<const unsigned char> b) {
return memcmp(a.data(), b.data(), 16);
int f3_impl(vsql::CustomArg a, vsql::CustomArg b) {
return memcmp(a.value().data(), b.value().data(), 16);
}

static constexpr const char kTestBadTypeName[] = "TESTBADTYPE";
Expand Down
20 changes: 4 additions & 16 deletions mysql-test/suite/villagesql/std_data/complex3_encode.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,25 +37,13 @@ void complex3_from_string(std::string_view from, vsql::CustomResult out) {
}

// TO_STRING: always return "(0,0)"
bool complex3_to_string(vsql::Span<const unsigned char> buf,
vsql::Span<char> to, size_t *to_length) {
(void)buf; // Unused - always return "(0,0)"

const char *result = "(0,0)";
size_t len = strlen(result);

if (to.size() < len + 1) {
return true; // Error
}

memcpy(to.data(), result, len);
*to_length = len;
return false; // Success
void complex3_to_string(vsql::CustomArg in, vsql::StringResult out) {
(void)in; // Unused - always return "(0,0)"
out.set("(0,0)");
}

// COMPARE: always returns 0 (equal)
int complex3_compare(vsql::Span<const unsigned char> a,
vsql::Span<const unsigned char> b) {
int complex3_compare(vsql::CustomArg a, vsql::CustomArg b) {
(void)a;
(void)b;
return 0;
Expand Down
23 changes: 12 additions & 11 deletions mysql-test/suite/villagesql/std_data/missing_params_fn.cc
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,21 @@ void faketype_encode(vsql::MaybeParams<FakeParams> &, std::string_view from,
out.set_length(n);
}

bool faketype_decode(vsql::Span<const unsigned char> data,
vsql::Span<char> out, size_t *out_len) {
size_t n = data.size() < out.size() ? data.size() : out.size();
memcpy(out.data(), data.data(), n);
*out_len = n;
return false;
void faketype_decode(vsql::CustomArg in, vsql::StringResult out) {
auto data = in.value();
auto buf = out.buffer();
size_t n = data.size() < buf.size() ? data.size() : buf.size();
memcpy(buf.data(), data.data(), n);
out.set_length(n);
}

int faketype_compare(vsql::Span<const unsigned char> a,
vsql::Span<const unsigned char> b) {
size_t n = a.size() < b.size() ? a.size() : b.size();
int r = memcmp(a.data(), b.data(), n);
int faketype_compare(vsql::CustomArg a, vsql::CustomArg b) {
auto va = a.value();
auto vb = b.value();
size_t n = va.size() < vb.size() ? va.size() : vb.size();
int r = memcmp(va.data(), vb.data(), n);
if (r != 0) return r;
return static_cast<int>(a.size()) - static_cast<int>(b.size());
return static_cast<int>(va.size()) - static_cast<int>(vb.size());
}

static constexpr const char kFakeTypeName[] = "FAKETYPE";
Expand Down
19 changes: 8 additions & 11 deletions mysql-test/suite/villagesql/std_data/no_default_type.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,16 @@ void no_default_encode(std::string_view from, vsql::CustomResult out) {
out.set_length(static_cast<size_t>(kLen));
}

bool no_default_decode(vsql::Span<const unsigned char> buffer,
vsql::Span<char> out, size_t *out_len) {
if (buffer.size() < static_cast<size_t>(kLen)) return true;
int written = snprintf(out.data(), out.size(), "(%u)", buffer[0]);
if (written < 0) return true;
*out_len = static_cast<size_t>(written);
return false;
void no_default_decode(vsql::CustomArg in, vsql::StringResult out) {
auto buffer = in.value();
if (buffer.size() < static_cast<size_t>(kLen)) return; // default ERROR
auto buf = out.buffer();
int written = snprintf(buf.data(), buf.size(), "(%u)", buffer[0]);
if (written < 0) return;
out.set_length(static_cast<size_t>(written));
}

int no_default_compare(vsql::Span<const unsigned char>,
vsql::Span<const unsigned char>) {
return 0;
}
int no_default_compare(vsql::CustomArg, vsql::CustomArg) { return 0; }

static constexpr const char kNoDefaultTypeName[] = "NO_DEFAULT_TYPE";

Expand Down
14 changes: 7 additions & 7 deletions mysql-test/suite/villagesql/std_data/testtype_full.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ void encode_testtype(std::string_view from, vsql::CustomResult out) {
out.set_length(kTestTypeLen);
}

bool decode_testtype_full(vsql::Span<const unsigned char> from,
vsql::Span<char> to, size_t *to_length) {
void decode_testtype_full(vsql::CustomArg in, vsql::StringResult out) {
auto from = in.value();
double real, imag;
memcpy(&real, from.data(), 8);
memcpy(&imag, from.data() + 8, 8);
*to_length = snprintf(to.data(), to.size(), "(%.17g,%.17g)", real, imag);
return false;
auto to = out.buffer();
size_t len = snprintf(to.data(), to.size(), "(%.17g,%.17g)", real, imag);
out.set_length(len);
}

int cmp_testtype(vsql::Span<const unsigned char> l,
vsql::Span<const unsigned char> r) {
return memcmp(l.data(), r.data(), kTestTypeLen);
int cmp_testtype(vsql::CustomArg l, vsql::CustomArg r) {
return memcmp(l.value().data(), r.value().data(), kTestTypeLen);
}

static constexpr const char kTestTypeName[] = "TESTTYPE";
Expand Down
14 changes: 7 additions & 7 deletions mysql-test/suite/villagesql/std_data/testtype_short.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,18 @@ void encode_testtype(std::string_view from, vsql::CustomResult out) {
out.set_length(kTestTypeLen);
}

bool decode_testtype_short(vsql::Span<const unsigned char> from,
vsql::Span<char> to, size_t *to_length) {
void decode_testtype_short(vsql::CustomArg in, vsql::StringResult out) {
auto from = in.value();
double real, imag;
memcpy(&real, from.data(), 8);
memcpy(&imag, from.data() + 8, 8);
*to_length = snprintf(to.data(), to.size(), "(%.6g,%.6g)", real, imag);
return false;
auto to = out.buffer();
size_t len = snprintf(to.data(), to.size(), "(%.6g,%.6g)", real, imag);
out.set_length(len);
}

int cmp_testtype(vsql::Span<const unsigned char> a,
vsql::Span<const unsigned char> b) {
return memcmp(a.data(), b.data(), kTestTypeLen);
int cmp_testtype(vsql::CustomArg a, vsql::CustomArg b) {
return memcmp(a.value().data(), b.value().data(), kTestTypeLen);
}

static constexpr const char kTestTypeName[] = "TESTTYPE";
Expand Down
28 changes: 15 additions & 13 deletions villagesql/examples/vsql-complex/src/complex.cc
Original file line number Diff line number Diff line change
Expand Up @@ -135,22 +135,23 @@ void complex2_from_string(std::string_view from, vsql::CustomResult out) {

// Decode: 16 bytes -> "(real,imag)" string
// COMPLEX -> STRING
bool complex_to_string(vsql::Span<const unsigned char> data,
vsql::Span<char> out, size_t *out_len) {
if (data.size() != kComplexSize) return true;
void complex_to_string(CustomArg in, StringResult out) {
auto data = in.value();
if (data.size() != kComplexSize) return; // wrapper default ERROR
Complex cx = load_complex(data.data());
int written = snprintf(out.data(), out.size(), "(%g,%g)", cx.re, cx.im);
if (written < 0 || static_cast<size_t>(written) >= out.size()) return true;
*out_len = static_cast<size_t>(written);
return false;
auto buf = out.buffer();
int written = snprintf(buf.data(), buf.size(), "(%g,%g)", cx.re, cx.im);
if (written < 0 || static_cast<size_t>(written) >= buf.size()) return;
out.set_length(static_cast<size_t>(written));
}

// Compare: (COMPLEX, COMPLEX) -> INT for ORDER BY, indexes
int complex_compare(vsql::Span<const unsigned char> a,
vsql::Span<const unsigned char> b) {
if (a.size() != kComplexSize || b.size() != kComplexSize) return 0;
Complex lhs = load_complex(a.data());
Complex rhs = load_complex(b.data());
int complex_compare(CustomArg a, CustomArg b) {
auto da = a.value();
auto db = b.value();
if (da.size() != kComplexSize || db.size() != kComplexSize) return 0;
Complex lhs = load_complex(da.data());
Complex rhs = load_complex(db.data());

// Compare real parts first
if (lhs.re < rhs.re) return -1;
Expand All @@ -165,7 +166,8 @@ int complex_compare(vsql::Span<const unsigned char> a,
// Canonicalizes -0 to +0 before hashing so that -0.0 and +0.0 hash to the
// same bucket. This allows COMPLEX2 to preserve -0 in storage while still
// working correctly with hash joins and EXCEPT operations.
size_t complex2_hash(vsql::Span<const unsigned char> data) {
size_t complex2_hash(CustomArg in) {
auto data = in.value();
if (data.size() != kComplexSize) return 0;
Complex cx = load_complex(data.data());
cx.canonicalize();
Expand Down
17 changes: 8 additions & 9 deletions villagesql/examples/vsql-simple/src/extension.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,17 @@ void bytearray_from_string(std::string_view from, CustomResult out) {
}

// to_string: binary -> string (copy 8 bytes)
bool bytearray_to_string(Span<const unsigned char> data, Span<char> out,
size_t *out_len) {
if (data.size() < kBytearrayLen || out.size() < kBytearrayLen) return true;
memcpy(out.data(), data.data(), kBytearrayLen);
*out_len = kBytearrayLen;
return false; // success
void bytearray_to_string(CustomArg in, StringResult out) {
auto data = in.value();
auto buf = out.buffer();
if (data.size() < kBytearrayLen || buf.size() < kBytearrayLen) return;
memcpy(buf.data(), data.data(), kBytearrayLen);
out.set_length(kBytearrayLen);
}

// Compare: lexicographic byte comparison
int bytearray_compare(Span<const unsigned char> a,
Span<const unsigned char> b) {
return memcmp(a.data(), b.data(), kBytearrayLen);
int bytearray_compare(CustomArg a, CustomArg b) {
return memcmp(a.value().data(), b.value().data(), kBytearrayLen);
}

// ROT13: apply ROT13 cipher to ASCII letters
Expand Down
47 changes: 25 additions & 22 deletions villagesql/examples/vsql-tvector/src/tvector.cc
Original file line number Diff line number Diff line change
Expand Up @@ -271,57 +271,60 @@ void tvector_from_string(vsql::MaybeParams<TVectorParams> &p,
// Decode: N * bpe bytes binary -> "[v1,v2,...,vN]" string.
// TVECTOR -> STRING
// Dimension and element type are read from type parameters.
bool tvector_to_string(const TVectorParams &p,
vsql::Span<const unsigned char> data,
vsql::Span<char> out, size_t *out_len) {
void tvector_to_string(vsql::CustomArgWith<TVectorParams> in,
vsql::StringResult out) {
const TVectorParams &p = in.params();
auto data = in.value();
const size_t bpe = p.bytes_per_elem;
if (data.size() != static_cast<size_t>(p.dimension) * bpe) return true;
if (data.size() != static_cast<size_t>(p.dimension) * bpe) return;

auto buf = out.buffer();
size_t pos = 0;
if (pos >= out.size()) return true;
out[pos++] = '[';
if (pos >= buf.size()) return;
buf[pos++] = '[';

for (size_t i = 0; i < static_cast<size_t>(p.dimension); i++) {
if (i > 0) {
if (pos >= out.size()) return true;
out[pos++] = ',';
if (pos >= buf.size()) return;
buf[pos++] = ',';
}
int written;
if (bpe == 8) {
double val = load_double(data.data() + i * bpe);
written = snprintf(out.data() + pos, out.size() - pos, "%.17g", val);
written = snprintf(buf.data() + pos, buf.size() - pos, "%.17g", val);
} else {
float val = load_float(data.data() + i * bpe);
written = snprintf(out.data() + pos, out.size() - pos, "%g", val);
written = snprintf(buf.data() + pos, buf.size() - pos, "%g", val);
}
if (written < 0 || pos + static_cast<size_t>(written) >= out.size())
return true;
if (written < 0 || pos + static_cast<size_t>(written) >= buf.size()) return;
pos += static_cast<size_t>(written);
}

if (pos >= out.size()) return true;
out[pos++] = ']';
if (pos >= buf.size()) return;
buf[pos++] = ']';

*out_len = pos;
return false;
out.set_length(pos);
}

// Compare: (TVECTOR, TVECTOR) -> INT for ORDER BY, indexes.
// Lexicographic element-by-element comparison.
// TODO(villagesql-performance): we can also consider having templated versions
// of these functions instead of using branches, then selecting the version to
// use with one branch.
int tvector_compare(const TVectorParams &p, vsql::Span<const unsigned char> a,
vsql::Span<const unsigned char> b) {
int tvector_compare(vsql::CustomArgWith<TVectorParams> a,
vsql::CustomArgWith<TVectorParams> b) {
const TVectorParams &p = a.params();
const unsigned char *da = a.value().data();
const unsigned char *db = b.value().data();
for (int64_t i = 0; i < p.dimension; i++) {
if (p.bytes_per_elem == 8) {
double v1 = load_double(a.data() + i * p.bytes_per_elem);
double v2 = load_double(b.data() + i * p.bytes_per_elem);
double v1 = load_double(da + i * p.bytes_per_elem);
double v2 = load_double(db + i * p.bytes_per_elem);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
} else {
float v1 = load_float(a.data() + i * p.bytes_per_elem);
float v2 = load_float(b.data() + i * p.bytes_per_elem);
float v1 = load_float(da + i * p.bytes_per_elem);
float v2 = load_float(db + i * p.bytes_per_elem);
if (v1 < v2) return -1;
if (v1 > v2) return 1;
}
Expand Down
Loading
Loading