in backend/query/ann_validator.cc [307:386]
absl::Status ANNValidator::VisitResolvedLimitOffsetScan(
const zetasql::ResolvedLimitOffsetScan* node) {
std::vector<const zetasql::ResolvedNode*> child_nodes;
const zetasql::ResolvedFunctionCall* last_ann_func = nullptr;
if (!GetAnnFunctionCall(node, last_ann_func, child_nodes).ok()) {
return zetasql::ResolvedASTVisitor::DefaultVisit(node);
}
ann_functions_.insert(last_ann_func);
std::vector<const Index*> indexes;
std::vector<zetasql::ResolvedColumn> not_null_columns;
bool is_force_index = false;
const zetasql::ResolvedScan* scan = nullptr;
ZETASQL_RETURN_IF_ERROR(GetNotNullColumns(child_nodes, scan, not_null_columns));
if (scan->Is<zetasql::ResolvedJoinScan>() && last_ann_func != nullptr) {
return error::ApproxDistanceInvalidShape(last_ann_func->function()->Name());
}
if (scan->Is<zetasql::ResolvedTableScan>() &&
!scan->GetAs<zetasql::ResolvedTableScan>()->hint_list().empty()) {
for (const auto& hint :
scan->GetAs<zetasql::ResolvedTableScan>()->hint_list()) {
if (absl::EqualsIgnoreCase(hint->name(), "force_index")) {
ZETASQL_RET_CHECK(hint->value()->Is<zetasql::ResolvedLiteral>());
indexes = schema_->FindIndexesUnderName(
hint->value()
->GetAs<zetasql::ResolvedLiteral>()
->value()
.string_value());
ZETASQL_RET_CHECK(indexes.size() == 1);
is_force_index = true;
if (!indexes[0]->is_vector_index() && last_ann_func != nullptr) {
return error::NotVectorIndexes(indexes[0]->Name());
}
}
}
}
if (last_ann_func == nullptr) {
return zetasql::ResolvedASTVisitor::DefaultVisit(node);
}
zetasql::ResolvedColumn ann_func_column;
zetasql::Value ann_func_value;
ZETASQL_RETURN_IF_ERROR(
GetANNFunctionArguments(last_ann_func, ann_func_column, ann_func_value));
ZETASQL_RETURN_IF_ERROR(ValidateFunctionArguments(ann_func_value, last_ann_func));
if (indexes.empty()) {
indexes = schema_->vector_indexes();
}
ZETASQL_ASSIGN_OR_RETURN(const Index* vec_index,
FindVectorIndex(indexes, ann_func_column, ann_func_value,
last_ann_func, is_force_index));
ZETASQL_RET_CHECK(vec_index->key_columns().size() == 1);
const KeyColumn* key_column = vec_index->key_columns()[0];
bool is_key_null_filtered = false;
for (const auto* column : vec_index->null_filtered_columns()) {
if (key_column->column()->Name() == column->Name()) {
is_key_null_filtered = true;
break;
}
}
if (is_key_null_filtered) {
bool is_not_null_column_found = false;
for (const auto& not_null_column : not_null_columns) {
if (vec_index->indexed_table()->Name() == not_null_column.table_name() &&
key_column->column()->Name() == not_null_column.name()) {
is_not_null_column_found = true;
break;
}
}
if (!is_not_null_column_found) {
return error::VectorIndexesUnusableNotNullFiltered(
vec_index->Name(), key_column->column()->Name());
}
}
return zetasql::ResolvedASTVisitor::DefaultVisit(node);
}