blob: bb64c938dd931390cd99cc5779396167a7bd07b3 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
**/
#include "cli/PrintToScreen.hpp"
#include <cmath>
#include <cstddef>
#include <cstdio>
#include <iomanip>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
#include "catalog/CatalogAttribute.hpp"
#include "catalog/CatalogRelation.hpp"
#include "storage/StorageBlock.hpp"
#include "storage/StorageBlockInfo.hpp"
#include "storage/StorageManager.hpp"
#include "storage/TupleIdSequence.hpp"
#include "storage/TupleStorageSubBlock.hpp"
#include "types/IntType.hpp"
#include "types/Type.hpp"
#include "types/TypedValue.hpp"
#include "utility/Macros.hpp"
#include "gflags/gflags.h"
using std::fprintf;
using std::fputc;
using std::size_t;
using std::string;
using std::vector;
namespace quickstep {
DEFINE_bool(printing_enabled, true,
"If true, print query results to screen normally. If false, skip "
"printing output (e.g. for benchmarking).");
int PrintToScreen::GetNumberOfDigits(int number) {
if (number > 0) {
return static_cast<int>(log10 (number)) + 1;
} else if (number < 0) {
return static_cast<int>(log10 ( abs(number) )) + 2;
} else {
return 1;
}
}
void PrintToScreen::PrintRelation(const CatalogRelation &relation,
StorageManager *storage_manager,
FILE *out) {
if (!FLAGS_printing_enabled) {
return;
}
vector<int> column_widths;
column_widths.reserve(relation.size());
for (CatalogRelation::const_iterator attr_it = relation.begin();
attr_it != relation.end();
++attr_it) {
// Printed column needs to be wide enough to print:
// 1. The attribute name (in the printed "header").
// 2. Any value of the attribute's Type.
// 3. If the attribute's Type is nullable, the 4-character string "NULL".
// We pick the largest of these 3 widths as the column width.
int column_width = static_cast<int>(attr_it->getDisplayName().length());
column_width = column_width < attr_it->getType().getPrintWidth()
? attr_it->getType().getPrintWidth()
: column_width;
column_width = attr_it->getType().isNullable() && (column_width < 4)
? 4
: column_width;
column_widths.push_back(column_width);
}
const string hbar = GenerateHBar(column_widths);
fprintf(out, "%s", hbar.c_str());
fputc('|', out);
vector<int>::const_iterator width_it = column_widths.begin();
CatalogRelation::const_iterator attr_it = relation.begin();
for (; width_it != column_widths.end(); ++width_it, ++attr_it) {
fprintf(out,
"%-*s|",
*width_it,
attr_it->getDisplayName().c_str());
}
fputc('\n', out);
fprintf(out, "%s", hbar.c_str());
std::vector<block_id> blocks = relation.getBlocksSnapshot();
for (const block_id current_block_id : blocks) {
BlockReference block = storage_manager->getBlock(current_block_id, relation);
const TupleStorageSubBlock &tuple_store = block->getTupleStorageSubBlock();
if (tuple_store.isPacked()) {
for (tuple_id tid = 0; tid <= tuple_store.getMaxTupleID(); ++tid) {
printTuple(tuple_store, tid, column_widths, out);
}
} else {
std::unique_ptr<TupleIdSequence> existence_map(tuple_store.getExistenceMap());
for (tuple_id tid : *existence_map) {
printTuple(tuple_store, tid, column_widths, out);
}
}
}
fprintf(out, "%s", hbar.c_str());
}
string PrintToScreen::GenerateHBar(const vector<int> &column_widths) {
string hbar("+");
for (const int width : column_widths) {
hbar.append(width, '-');
hbar.push_back('+');
}
hbar.push_back('\n');
return hbar;
}
void PrintToScreen::printTuple(const TupleStorageSubBlock &tuple_store,
const tuple_id tid,
const vector<int> &column_widths,
FILE *out) {
DEBUG_ASSERT(tuple_store.hasTupleWithID(tid));
fputc('|', out);
const CatalogRelationSchema &relation = tuple_store.getRelation();
vector<int>::const_iterator width_it = column_widths.begin();
CatalogRelation::const_iterator attr_it = relation.begin();
for (; attr_it != relation.end(); ++attr_it, ++width_it) {
TypedValue value(tuple_store.getAttributeValueTyped(tid, attr_it->getID()));
if (value.isNull()) {
fprintf(out,
"%*s",
*width_it,
"NULL");
} else {
attr_it->getType().printValueToFile(value, out, *width_it);
}
fputc('|', out);
}
fputc('\n', out);
}
std::size_t PrintToScreen::GetNumTuplesInRelation(
const CatalogRelation &relation, StorageManager *storage_manager) {
const std::vector<block_id> &blocks = relation.getBlocksSnapshot();
std::size_t total_num_tuples = 0;
for (block_id block : blocks) {
total_num_tuples +=
storage_manager->getBlock(block, relation)->getNumTuples();
}
return total_num_tuples;
}
void PrintToScreen::PrintOutputSize(const CatalogRelation &relation,
StorageManager *storage_manager,
FILE *out) {
const std::size_t num_rows = GetNumTuplesInRelation(relation, storage_manager);
fprintf(out,
"(%lu %s)\n",
num_rows,
(num_rows == 1) ? "row" : "rows");
}
} // namespace quickstep