void InformationSchemaCatalog::FillColumnsTable()

in backend/query/information_schema_catalog.cc [878:1087]


void InformationSchemaCatalog::FillColumnsTable() {
  auto columns = tables_by_name_.at(GetNameForDialect(kColumns)).get();

  // Add table rows.
  std::vector<std::vector<zetasql::Value>> rows;
  absl::flat_hash_map<std::string, zetasql::Value> specific_kvs;
  for (const Table* table : default_schema_->tables()) {
    int pos = 1;
    for (const Column* column : table->columns()) {
      if (dialect_ == DatabaseDialect::POSTGRESQL) {
        specific_kvs[kColumnDefault] =
            column->has_default_value() && !column->is_identity_column()
                ? String(column->original_expression().value())
                : NullString();

        const zetasql::Type* type = column->GetType();
        if (column->has_allows_commit_timestamp()) {
          specific_kvs[kDataType] = String(kSpannerCommitTimestamp);
          specific_kvs[kSpannerType] = String(kSpannerCommitTimestamp);
        } else {
          specific_kvs[kDataType] = PGDataType(type);
          specific_kvs[kSpannerType] = GetSpannerType(column);
        }

        specific_kvs[kCharacterMaximumLength] =
            (!type->IsArray() && column->declared_max_length() != std::nullopt)
                ? Int64(column->declared_max_length().value())
                : NullInt64();

        specific_kvs[kNumericPrecision] = GetPGNumericPrecision(type);
        specific_kvs[kNumericPrecisionRadix] = GetPGNumericPrecisionRadix(type);
        specific_kvs[kNumericScale] = type->IsInt64() ? Int64(0) : NullInt64();

        specific_kvs[kGenerationExpression] =
            column->is_generated()
                ? String(column->original_expression().value())
                : NullString();
      } else {
        specific_kvs[kGenerationExpression] = NullString();
        if (column->is_generated()) {
          absl::string_view expression = column->expression().value();
          absl::ConsumePrefix(&expression, "(");
          absl::ConsumeSuffix(&expression, ")");
          specific_kvs[kGenerationExpression] = String(expression);
        }

        specific_kvs[kColumnDefault] =
            (column->has_default_value() && !column->is_identity_column())
                ? String(column->expression().value())
                : NullString();

        specific_kvs[kDataType] = NullString();
        specific_kvs[kSpannerType] = GetSpannerType(column);
      }

      const auto& [table_schema_part, table_name_part] =
          GetSchemaAndNameForInformationSchema(table->Name());
      specific_kvs[kTableCatalog] = DialectTableCatalog();
      specific_kvs[kTableSchema] = String(table_schema_part);
      specific_kvs[kTableName] = String(table_name_part);
      specific_kvs[kColumnName] = String(column->Name());
      specific_kvs[kOrdinalPosition] = Int64(pos++);
      specific_kvs[kIsNullable] = String(column->is_nullable() ? kYes : kNo);
      specific_kvs[kIsGenerated] =
          String(column->is_generated() ? kAlways : kNever);
      if (column->is_generated()) {
        specific_kvs[kIsStored] =
            column->is_stored() ? String(kYes) : String(kNo);
      } else {
        specific_kvs[kIsStored] = NullString();
      }
      // Identity column fields.
      specific_kvs[kIsIdentity] =
          String(column->is_identity_column() ? kYes : kNo);
      specific_kvs[kSpannerState] = String(kCommitted);
      specific_kvs[kIdentityGeneration] = NullString();
      specific_kvs[kIdentityKind] = NullString();
      specific_kvs[kIdentityStartWithCounter] = NullString();
      specific_kvs[kIdentitySkipRangeMin] = NullString();
      specific_kvs[kIdentitySkipRangeMax] = NullString();
      if (column->is_identity_column()) {
        specific_kvs[kIdentityGeneration] = String(kByDefault);
        if (!column->sequences_used().empty()) {
          const Sequence* seq =
              static_cast<const Sequence*>(column->sequences_used().at(0));
          if (!seq->use_default_sequence_kind_option()) {
            specific_kvs[kIdentityKind] = String(kBitReversedPositiveSequence);
          }
          specific_kvs[kIdentityStartWithCounter] =
              seq->start_with_counter().has_value()
                  ? String(absl::StrCat(*seq->start_with_counter()))
                  : NullString();
          specific_kvs[kIdentitySkipRangeMin] =
              seq->skip_range_min().has_value()
                  ? String(absl::StrCat(*seq->skip_range_min()))
                  : NullString();
          specific_kvs[kIdentitySkipRangeMax] =
              seq->skip_range_max().has_value()
                  ? String(absl::StrCat(*seq->skip_range_max()))
                  : NullString();
        }
      }

      rows.push_back(GetRowFromRowKVs(columns, specific_kvs));
      specific_kvs.clear();
    }
  }

  // Add columns for views.
  for (const View* view : default_schema_->views()) {
    int pos = 1;
    for (const View::Column& column : view->columns()) {
      if (dialect_ == DatabaseDialect::POSTGRESQL) {
        // Emulator's View::Column doesn't store the length so we pass the
        // length in as a std::nullopt.
        specific_kvs[kDataType] = PGDataType(column.type);
        specific_kvs[kSpannerType] = GetSpannerType(column.type, std::nullopt);

        // Emulator's View::Column doesn't store the length so we assume the
        // length is the max string or byte length.
        // TODO: Update the View::Column to store the actual
        // length.
        specific_kvs[kCharacterMaximumLength] = NullInt64();

        specific_kvs[kNumericPrecision] = GetPGNumericPrecision(column.type);
        specific_kvs[kNumericPrecisionRadix] =
            GetPGNumericPrecisionRadix(column.type);
        specific_kvs[kNumericScale] =
            column.type->IsInt64() ? Int64(0) : NullInt64();
      } else {
        specific_kvs[kDataType] = NullString();
        specific_kvs[kSpannerType] = GetSpannerType(column.type, 0);
      }

      const auto& [view_schema_part, view_name_part] =
          GetSchemaAndNameForInformationSchema(view->Name());
      specific_kvs[kTableCatalog] = DialectTableCatalog();
      specific_kvs[kTableSchema] = String(view_schema_part);
      specific_kvs[kTableName] = String(view_name_part);
      specific_kvs[kColumnName] = String(column.name);
      specific_kvs[kOrdinalPosition] = Int64(pos++);
      specific_kvs[kColumnDefault] = NullBytes();
      specific_kvs[kIsNullable] = String(kYes);
      specific_kvs[kIsGenerated] = String(kNever);
      specific_kvs[kGenerationExpression] = NullString();
      specific_kvs[kIsStored] = NullString();
      specific_kvs[kSpannerState] = String(kCommitted);
      specific_kvs[kIsIdentity] = String(kNo);
      specific_kvs[kIdentityGeneration] = NullString();
      specific_kvs[kIdentityKind] = NullString();
      specific_kvs[kIdentityStartWithCounter] = NullString();
      specific_kvs[kIdentitySkipRangeMin] = NullString();
      specific_kvs[kIdentitySkipRangeMax] = NullString();

      rows.push_back(GetRowFromRowKVs(columns, specific_kvs));
      specific_kvs.clear();
    }
  }

  // Add columns for the tables that live inside INFORMATION_SCHEMA.
  for (const auto& table : this->tables()) {
    int pos = 1;
    for (int i = 0; i < table->NumColumns(); ++i) {
      const auto* column = table->GetColumn(i);
      const auto& metadata = GetColumnMetadata(dialect_, table, column);

      if (dialect_ == DatabaseDialect::POSTGRESQL) {
        const zetasql::Type* type = column->GetType();
        // Information schema metadata doesn't store the length of a character
        // varying or bytea type. So we always pass in std::nullopt as the
        // length.
        specific_kvs[kDataType] = PGDataType(type);
        specific_kvs[kSpannerType] = GetSpannerType(type, std::nullopt);

        specific_kvs[kCharacterMaximumLength] = NullInt64();
        specific_kvs[kNumericPrecision] = GetPGNumericPrecision(type);
        specific_kvs[kNumericPrecisionRadix] = GetPGNumericPrecisionRadix(type);
        specific_kvs[kNumericScale] = type->IsInt64() ? Int64(0) : NullInt64();
      } else {
        specific_kvs[kDataType] = NullString();
        specific_kvs[kSpannerType] = String(metadata.spanner_type);
      }

      specific_kvs[kTableCatalog] = DialectTableCatalog();
      specific_kvs[kTableSchema] =
          String(GetNameForDialect(kInformationSchema));
      specific_kvs[kTableName] = String(GetNameForDialect(table->Name()));
      specific_kvs[kColumnName] = String(GetNameForDialect(column->Name()));
      specific_kvs[kOrdinalPosition] = Int64(pos++);
      specific_kvs[kColumnDefault] = NullBytes();
      specific_kvs[kIsNullable] = String(metadata.is_nullable);
      specific_kvs[kIsGenerated] = String(kNever);
      specific_kvs[kGenerationExpression] = NullString();
      specific_kvs[kIsStored] = NullString();
      specific_kvs[kSpannerState] = NullString();
      specific_kvs[kIsIdentity] = String(kNo);
      specific_kvs[kIdentityGeneration] = NullString();
      specific_kvs[kIdentityKind] = NullString();
      specific_kvs[kIdentityStartWithCounter] = NullString();
      specific_kvs[kIdentitySkipRangeMin] = NullString();
      specific_kvs[kIdentitySkipRangeMax] = NullString();

      rows.push_back(GetRowFromRowKVs(columns, specific_kvs));
      specific_kvs.clear();
    }
  }

  // Add table to catalog.
  columns->SetContents(rows);
}