fix(sql) fix binary detection + fix custom types (#17635)

This commit is contained in:
Ciro Spaciari
2025-02-24 20:07:16 -08:00
committed by GitHub
parent 211824bb3e
commit 09ab840114
5 changed files with 173 additions and 42 deletions

View File

@@ -45,6 +45,7 @@ pub const AnyPostgresError = error{
UnsupportedIntegerSize,
UnsupportedArrayFormat,
UnsupportedNumericFormat,
UnknownFormatCode,
};
pub fn postgresErrorToJS(globalObject: *JSC.JSGlobalObject, message: ?[]const u8, err: AnyPostgresError) JSValue {
@@ -77,6 +78,7 @@ pub fn postgresErrorToJS(globalObject: *JSC.JSGlobalObject, message: ?[]const u8
error.UnsupportedArrayFormat => JSC.Error.ERR_POSTGRES_UNSUPPORTED_ARRAY_FORMAT,
error.UnsupportedIntegerSize => JSC.Error.ERR_POSTGRES_UNSUPPORTED_INTEGER_SIZE,
error.UnsupportedNumericFormat => JSC.Error.ERR_POSTGRES_UNSUPPORTED_NUMERIC_FORMAT,
error.UnknownFormatCode => JSC.Error.ERR_POSTGRES_UNKNOWN_FORMAT_CODE,
error.JSError => {
return globalObject.takeException(error.JSError);
},
@@ -916,9 +918,11 @@ pub const PostgresRequest = struct {
var iter = QueryBindingIterator.init(values_array, columns_value, globalObject);
for (0..len) |i| {
const tag: types.Tag = @enumFromInt(@as(short, @intCast(parameter_fields[i])));
const parameter_field = parameter_fields[i];
const is_custom_type = std.math.maxInt(short) < parameter_field;
const tag: types.Tag = if (is_custom_type) .text else @enumFromInt(@as(short, @intCast(parameter_field)));
const force_text = tag.isBinaryFormatSupported() and brk: {
const force_text = is_custom_type or (tag.isBinaryFormatSupported() and brk: {
iter.to(@truncate(i));
if (iter.next()) |value| {
break :brk value.isString();
@@ -927,7 +931,7 @@ pub const PostgresRequest = struct {
return error.InvalidQueryBinding;
}
break :brk false;
};
});
if (force_text) {
// If they pass a value as a string, let's avoid attempting to
@@ -952,7 +956,9 @@ pub const PostgresRequest = struct {
iter.to(0);
var i: usize = 0;
while (iter.next()) |value| : (i += 1) {
const tag: types.Tag = @enumFromInt(@as(short, @intCast(parameter_fields[i])));
const parameter_field = parameter_fields[i];
const is_custom_type = std.math.maxInt(short) < parameter_field;
const tag: types.Tag = if (is_custom_type) .text else @enumFromInt(@as(short, @intCast(parameter_field)));
if (value.isEmptyOrUndefinedOrNull()) {
debug(" -> NULL", .{});
// As a special case, -1 indicates a
@@ -2835,8 +2841,8 @@ pub const PostgresSQLConnection = struct {
return DataCell{ .tag = .array, .value = .{ .array = .{ .ptr = array.items.ptr, .len = @truncate(array.items.len), .cap = @truncate(array.capacity) } } };
}
pub fn fromBytes(binary: bool, bigint: bool, oid: int4, bytes: []const u8, globalObject: *JSC.JSGlobalObject) !DataCell {
switch (@as(types.Tag, @enumFromInt(@as(short, @intCast(oid))))) {
pub fn fromBytes(binary: bool, bigint: bool, oid: types.Tag, bytes: []const u8, globalObject: *JSC.JSGlobalObject) !DataCell {
switch (oid) {
// TODO: .int2_array, .float8_array
inline .int4_array, .float4_array => |tag| {
if (binary) {
@@ -3294,8 +3300,9 @@ pub const PostgresSQLConnection = struct {
if (is_raw) {
cell.* = DataCell.raw(optional_bytes);
} else {
const tag = if (std.math.maxInt(short) < oid) .text else @as(types.Tag, @enumFromInt(@as(short, @intCast(oid))));
cell.* = if (optional_bytes) |data|
try DataCell.fromBytes(this.binary, this.bigint, oid, data.slice(), this.globalObject)
try DataCell.fromBytes((field.binary or this.binary) and tag.isBinaryFormatSupported(), this.bigint, tag, data.slice(), this.globalObject)
else
DataCell{
.tag = .null,