blob: e9db628a72a47b1466644f3c121e02b21d419ead [file] [log] [blame]
/**
* Copyright 2016, Quickstep Research Group, Computer Sciences Department,
* University of Wisconsin—Madison.
*
* Licensed 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/CommandExecutor.hpp"
#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <memory>
#include <string>
#include <vector>
#include "catalog/CatalogAttribute.hpp"
#include "catalog/CatalogDatabase.hpp"
#include "catalog/CatalogRelation.hpp"
#include "catalog/CatalogRelationSchema.hpp"
#include "cli/PrintToScreen.hpp"
#include "parser/ParseStatement.hpp"
#include "utility/PtrVector.hpp"
#include "utility/Macros.hpp"
#include "utility/SqlError.hpp"
#include "gflags/gflags.h"
#include "glog/logging.h"
using std::fprintf;
using std::fputc;
using std::fputs;
using std::size_t;
using std::string;
using std::vector;
namespace quickstep {
namespace cli {
namespace {
namespace C = ::quickstep::cli;
void executeDescribeDatabase(
const PtrVector<ParseString> *arguments,
const CatalogDatabase &catalog_database, FILE *out) {
// Column width initialized to 6 to take into account the header name
// and the column value table
int max_column_width = C::kInitMaxColumnWidth;
const CatalogRelation *relation;
if (arguments->size() == 0) {
for (const CatalogRelation &rel : catalog_database) {
max_column_width =
std::max(static_cast<int>(rel.getName().length()), max_column_width);
}
} else {
const ParseString &table_name = arguments->front();
const std::string &table_name_val = table_name.value();
relation = catalog_database.getRelationByName(table_name_val);
if (relation == nullptr) {
THROW_SQL_ERROR_AT(&(arguments->front())) << " Unrecognized relation " << table_name_val;
}
max_column_width = std::max(static_cast<int>(relation->getName().length()),
max_column_width);
}
// Only if we have relations work on the printing logic.
if (catalog_database.size() > 0) {
vector<int> column_widths;
column_widths.push_back(max_column_width+1);
column_widths.push_back(C::kInitMaxColumnWidth+1);
fputs(" List of relations\n\n", out);
fprintf(out, "%-*s |", max_column_width+1, " Name");
fprintf(out, "%-*s\n", C::kInitMaxColumnWidth, " Type");
PrintToScreen::printHBar(column_widths, out);
// If there are no argument print the entire list of tables
// else print the particular table only.
if (arguments->size() == 0) {
for (const CatalogRelation &rel : catalog_database) {
fprintf(out, " %-*s |", max_column_width, rel.getName().c_str());
fprintf(out, " %-*s\n", C::kInitMaxColumnWidth, "table");
}
} else {
fprintf(out, " %-*s |", max_column_width, relation->getName().c_str());
fprintf(out, " %-*s\n", C::kInitMaxColumnWidth, "table");
}
fputc('\n', out);
}
}
void executeDescribeTable(
const PtrVector<ParseString> *arguments,
const CatalogDatabase &catalog_database, FILE *out) {
const ParseString &table_name = arguments->front();
const std::string &table_name_val = table_name.value();
const CatalogRelation *relation =
catalog_database.getRelationByName(table_name_val);
if (relation == nullptr) {
THROW_SQL_ERROR_AT(&(arguments->front())) << " Unrecognized relation " << table_name_val;
}
vector<int> column_widths;
int max_attr_column_width = C::kInitMaxColumnWidth;
int max_type_column_width = C::kInitMaxColumnWidth;
for (const CatalogAttribute &attr : *relation) {
// 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.
max_attr_column_width =
std::max(max_attr_column_width,
static_cast<int>(attr.getDisplayName().length()));
max_type_column_width =
std::max(max_type_column_width,
static_cast<int>(attr.getType().getName().length()));
}
// Add room for one extra character to allow spacing between the column ending and the vertical bar
column_widths.push_back(max_attr_column_width+1);
column_widths.push_back(max_type_column_width+1);
fprintf(out, "%*s \"%s\"\n", C::kInitMaxColumnWidth, "Table", table_name_val.c_str());
fprintf(out, "%-*s |", max_attr_column_width+1, " Column");
fprintf(out, "%-*s\n", max_type_column_width+1, " Type");
PrintToScreen::printHBar(column_widths, out);
for (const CatalogAttribute &attr : *relation) {
fprintf(out, " %-*s |", max_attr_column_width,
attr.getDisplayName().c_str());
fprintf(out, " %-*s\n", max_type_column_width,
attr.getType().getName().c_str());
}
// TODO(rogers): Add handlers for partitioning information.
if (relation->hasIndexScheme()) {
fprintf(out, "%*s\n", C::kInitMaxColumnWidth+2, " Indexes");
const quickstep::IndexScheme &index_scheme = relation->getIndexScheme();
for (auto index_it = index_scheme.begin(); index_it != index_scheme.end();
++index_it) {
fprintf(out, " \"%-*s\" %s", static_cast<int>(index_it->first.length()),
index_it->first.c_str(),
index_it->second.IndexSubBlockType_Name(
index_it->second.sub_block_type()).c_str());
fputc(' ', out);
fputc('(', out);
fprintf(out, "%s", relation->getAttributeById(index_it->second.indexed_attribute_ids(0))
->getDisplayName().c_str());
for (std::size_t i = 1; i < static_cast<std::size_t>(index_it->second.indexed_attribute_ids_size()); ++i) {
const char *attribute_display_name = relation->getAttributeById(
index_it->second.indexed_attribute_ids(i))
->getDisplayName().c_str();
fprintf(out, ", %s", attribute_display_name);
}
fputc(')', out);
fputc('\n', out);
}
}
}
} // namespace
void executeCommand(const ParseStatement &statement,
const CatalogDatabase &catalog_database,
FILE *out) {
const ParseCommand &command = static_cast<const ParseCommand &>(statement);
const PtrVector<ParseString> *arguments = command.arguments();
const std::string &command_str = command.command()->value();
if (command_str == C::kDescribeDatabaseCommand) {
executeDescribeDatabase(arguments, catalog_database, out);
} else if (command_str == C::kDescribeTableCommand) {
if (arguments->size() == 0) {
executeDescribeDatabase(arguments, catalog_database, out);
} else {
executeDescribeTable(arguments, catalog_database, out);
}
} else {
THROW_SQL_ERROR_AT(command.command()) << "Invalid Command";
}
}
} // namespace cli
} // namespace quickstep