in src/bun.js/bindings/sqlite/JSSQLStatement.cpp [828:985]
static JSC::JSValue rebindObject(JSC::JSGlobalObject* globalObject, SQLiteBindingsMap& bindings, JSC::JSObject* target, JSC::ThrowScope& scope, sqlite3* db, sqlite3_stmt* stmt, bool clone, bool safeIntegers)
{
int count = 0;
JSC::VM& vm = globalObject->vm();
auto& structure = *target->structure();
bindings.ensureNamesLoaded(vm, stmt);
const auto& bindingNames = bindings.bindingNames;
size_t size = bindings.count;
const bool trimLeadingPrefix = bindings.trimLeadingPrefix;
const bool throwOnMissing = trimLeadingPrefix;
// Did they reorder the columns?
//
// { ?2: "foo", ?1: "bar" }
//
if (UNLIKELY(bindings.hasOutOfOrderNames)) {
const auto& getValue = [&](const char* name, size_t i) -> JSValue {
JSValue value = {};
if (name == nullptr) {
return target->getDirectIndex(globalObject, i);
}
if (trimLeadingPrefix) {
name += 1;
}
const WTF::String str = WTF::String::fromUTF8ReplacingInvalidSequences({ reinterpret_cast<const unsigned char*>(name), strlen(name) });
if (trimLeadingPrefix && name[0] >= '0' && name[0] <= '9') {
auto integer = WTF::parseInteger<int32_t>(str, 10);
if (integer.has_value()) {
return target->getDirectIndex(globalObject, integer.value() - 1);
}
}
const auto identifier = Identifier::fromString(vm, str);
PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
if (!target->getOwnNonIndexPropertySlot(vm, &structure, identifier, slot)) {
return JSValue();
}
if (LIKELY(!slot.isTaintedByOpaqueObject())) {
return slot.getValue(globalObject, identifier);
}
return target->get(globalObject, identifier);
};
for (size_t i = 0; i < size; i++) {
auto* name = sqlite3_bind_parameter_name(stmt, i + 1);
JSValue value = getValue(name, i);
if (!value && !scope.exception()) {
if (throwOnMissing) {
throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, reinterpret_cast<const unsigned char*>(name), "\""_s)));
} else {
continue;
}
}
RETURN_IF_EXCEPTION(scope, JSValue());
if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
return JSValue();
}
RETURN_IF_EXCEPTION(scope, {});
count++;
}
}
// Does it only contain indexed properties?
//
// { 0: "foo", 1: "bar", "2": "baz" }
//
else if (UNLIKELY(bindings.isOnlyIndexed)) {
for (size_t i = 0; i < size; i++) {
JSValue value = target->getDirectIndex(globalObject, i);
if (!value && !scope.exception()) {
if (throwOnMissing) {
throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, i + 1, "\""_s)));
} else {
continue;
}
}
RETURN_IF_EXCEPTION(scope, JSValue());
if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
return JSValue();
}
RETURN_IF_EXCEPTION(scope, {});
count++;
}
}
// Is it a simple object with no getters or setters?
//
// { foo: "bar", baz: "qux" }
//
else if (target->canUseFastGetOwnProperty(structure)) {
for (size_t i = 0; i < size; i++) {
const auto& property = bindingNames[i];
JSValue value = property.isEmpty() ? target->getDirectIndex(globalObject, i) : target->fastGetOwnProperty(vm, structure, bindingNames[i]);
if (!value && !scope.exception()) {
if (throwOnMissing) {
throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, property.isEmpty() ? String::number(i) : property.string(), "\""_s)));
} else {
continue;
}
}
RETURN_IF_EXCEPTION(scope, JSValue());
if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
return JSValue();
}
RETURN_IF_EXCEPTION(scope, {});
count++;
}
} else {
for (size_t i = 0; i < size; i++) {
PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
const auto& property = bindingNames[i];
bool hasProperty = property.isEmpty() ? target->methodTable()->getOwnPropertySlotByIndex(target, globalObject, i, slot) : target->methodTable()->getOwnPropertySlot(target, globalObject, property, slot);
if (!hasProperty && !scope.exception()) {
if (throwOnMissing) {
throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, property.isEmpty() ? String::number(i) : property.string(), "\""_s)));
} else {
continue;
}
}
RETURN_IF_EXCEPTION(scope, JSValue());
JSValue value;
if (LIKELY(!slot.isTaintedByOpaqueObject()))
value = slot.getValue(globalObject, property);
else {
value = target->get(globalObject, property);
RETURN_IF_EXCEPTION(scope, JSValue());
}
RETURN_IF_EXCEPTION(scope, JSValue());
if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
return JSValue();
}
RETURN_IF_EXCEPTION(scope, {});
count++;
}
}
return jsNumber(count);
}