1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
|
//===----------------------------------------------------------------------===//
// DuckDB
//
// shell_state.hpp
//
//
//===----------------------------------------------------------------------===//
#pragma once
#include <vector>
#include <string>
#include <cstdint>
#include <memory>
#include "duckdb/common/string_util.hpp"
#include "duckdb/common/unique_ptr.hpp"
#include "duckdb/common/optional_ptr.hpp"
#include "duckdb/parser/sql_statement.hpp"
#include "duckdb/main/query_result.hpp"
#include "duckdb/common/atomic.hpp"
#include "duckdb.hpp"
namespace duckdb_shell {
using duckdb::make_uniq;
using duckdb::MaterializedQueryResult;
using duckdb::string;
using duckdb::StringUtil;
using duckdb::unique_ptr;
using duckdb::vector;
struct ColumnarResult;
struct RowResult;
class ShellRenderer;
using duckdb::atomic;
using duckdb::ErrorData;
using duckdb::KeywordHelper;
using duckdb::optional_idx;
using duckdb::optional_ptr;
using duckdb::SQLIdentifier;
using duckdb::SQLString;
using duckdb::unordered_map;
struct ShellState;
using duckdb::InternalException;
using duckdb::InvalidInputException;
using duckdb::to_string;
struct Prompt;
struct ShellProgressBar;
struct PagerState;
struct ShellTableInfo;
struct RenderingQueryResult;
enum class HighlightElementType : uint32_t;
using idx_t = uint64_t;
enum class RenderMode : uint32_t {
LINE = 0, /* One column per line. Blank line between records */
COLUMN, /* One record per line in neat columns */
LIST, /* One record per line with a separator */
SEMI, /* Same as RenderMode::List but append ";" to each line */
HTML, /* Generate an XHTML table */
INSERT, /* Generate SQL "insert" statements */
QUOTE, /* Quote values as for SQL */
TCL, /* Generate ANSI-C or TCL quoted elements */
CSV, /* Quote strings, numbers are plain */
EXPLAIN, /* Like RenderMode::Column, but do not truncate data */
DESCRIBE, /* Special DESCRIBE Renderer */
ASCII, /* Use ASCII unit and record separators (0x1F/0x1E) */
PRETTY, /* Pretty-print schemas */
EQP, /* Converts EXPLAIN QUERY PLAN output into a graph */
JSON, /* Output JSON */
MARKDOWN, /* Markdown formatting */
TABLE, /* MySQL-style table formatting */
BOX, /* Unicode box-drawing characters */
LATEX, /* Latex tabular formatting */
TRASH, /* Discard output */
JSONLINES, /* Output JSON Lines */
DUCKBOX /* Unicode box drawing - using DuckDB's own renderer */
};
enum class PrintOutput { STDOUT, STDERR };
enum class InputMode { STANDARD, FILE, DUCKDB_RC };
enum class LargeNumberRendering { NONE = 0, FOOTER = 1, ALL = 2, DEFAULT = 3 };
/*
** These are the allowed shellFlgs values
*/
enum class ShellFlags : uint32_t {
SHFLG_Newlines = 0x00000010, /* .dump --newline flag */
SHFLG_CountChanges = 0x00000020, /* .changes setting */
SHFLG_Echo = 0x00000040, /* .echo or --echo setting */
SHFLG_HeaderSet = 0x00000080 /* .header has been used */
};
enum class ShellOpenFlags { EXIT_ON_FAILURE, KEEP_ALIVE_ON_FAILURE };
enum class SuccessState { SUCCESS, FAILURE };
enum class OptionType { DEFAULT, ON, OFF };
enum class StartupText { ALL, VERSION, NONE };
enum class ReadLineVersion { LINENOISE, FALLBACK };
enum class PagerMode { PAGER_AUTOMATIC, PAGER_ON, PAGER_OFF };
enum class MetadataResult : uint8_t { SUCCESS = 0, FAIL = 1, EXIT = 2, PRINT_USAGE = 3 };
enum class HighlightMode : uint32_t { AUTOMATIC, MIXED_MODE, DARK_MODE, LIGHT_MODE };
enum class ExecuteSQLSingleValueResult {
SUCCESS,
EXECUTION_ERROR,
EMPTY_RESULT,
MULTIPLE_ROWS,
MULTIPLE_COLUMNS,
NULL_RESULT
};
typedef MetadataResult (*metadata_command_t)(ShellState &state, const vector<string> &args);
struct CommandLineOption {
const char *option;
idx_t argument_count;
const char *arguments;
metadata_command_t pre_init_callback;
metadata_command_t post_init_callback;
const char *description;
};
struct MetadataCommand {
const char *command;
idx_t argument_count;
metadata_command_t callback;
const char *usage;
const char *description;
idx_t match_size;
const char *extra_description;
};
struct ShellColumnInfo {
string column_name;
string column_type;
bool is_primary_key = false;
bool is_not_null = false;
bool is_unique = false;
string default_value;
};
struct ShellTableInfo {
string database_name;
string schema_name;
string table_name;
optional_idx estimated_size;
bool is_view = false;
vector<ShellColumnInfo> columns;
};
enum class BailOnError { AUTOMATIC, BAIL_ON_ERROR, DONT_BAIL_ON_ERROR };
/*
** State information about the database connection is contained in an
** instance of the following structure.
*/
struct ShellState {
public:
unique_ptr<duckdb::DuckDB> db; /* The database */
unique_ptr<duckdb::Connection> conn; /* The primary connection to the database */
duckdb::DBConfig config; /* Config used for opening the database */
uint8_t doXdgOpen = 0; /* Invoke start/open/xdg-open in output_reset() */
int outCount = 0; /* Revert to stdout when reaching zero */
int lineno = 0; /* Line number of last line read from in */
FILE *in = nullptr; /* Read commands from this stream */
FILE *out = nullptr; /* Write results here */
int nErr = 0; /* Number of errors seen */
RenderMode mode = RenderMode::LINE; /* An output mode setting */
RenderMode modePrior = RenderMode::LINE; /* Saved mode */
RenderMode cMode = RenderMode::LINE; /* temporary output mode for the current query */
RenderMode normalMode = RenderMode::LINE; /* Output mode before ".explain on" */
bool showHeader = false; /* True to show column names in List or Column mode */
uint32_t shellFlgs = 0; /* Various flags */
uint32_t priorShFlgs = 0; /* Saved copy of flags */
int64_t szMax = 0; /* --maxsize argument to .open */
string zDestTable; /* Name of destination table when RenderMode::Insert */
string zTempFile; /* Temporary file that might need deleting */
string colSeparator; /* Column separator character for several modes */
string rowSeparator; /* Row separator character for RenderMode::Ascii */
string colSepPrior; /* Saved column separator */
string rowSepPrior; /* Saved row separator */
vector<int> colWidth; /* Requested width of each column in columnar modes */
string nullValue; /* The text to print when a NULL comes back from the database */
int columns = 0; /* Column-wise DuckBox rendering */
string outfile; /* Filename for *out */
string zDbFilename; /* name of the database file */
FILE *pLog = nullptr; /* Write log output here */
size_t max_rows = 0; /* The maximum number of rows to render in DuckBox mode */
size_t max_width = 0; /* The maximum number of characters to render horizontally in DuckBox mode */
//! The maximum number of rows to analyze in order to determine column widths in DuckBox mode
idx_t max_analyze_rows = 0;
//! Decimal separator (if any)
char decimal_separator = '\0';
//! Thousand separator (if any)
char thousand_separator = '\0';
//! When to use formatting of large numbers (in DuckBox mode)
LargeNumberRendering large_number_rendering = LargeNumberRendering::DEFAULT;
//! The command to execute when `-ui` is passed in
string ui_command = "CALL start_ui()";
idx_t last_changes = 0;
idx_t total_changes = 0;
bool readStdin = true;
string initFile;
bool run_init = true;
unique_ptr<duckdb::MaterializedQueryResult> last_result;
//! If the following flag is set, then command execution stops at an error
BailOnError bail = BailOnError::AUTOMATIC;
//! Table name when rendering a DESCRIBE statement
string describe_table_name;
/*
** Treat stdin as an interactive input if the following variable
** is true. Otherwise, assume stdin is connected to a file or pipe.
*/
bool stdin_is_interactive = true;
/*
** On Windows systems we have to know if standard output is a console
** in order to translate UTF-8 into MBCS. The following variable is
** true if translation is required.
*/
bool stdout_is_console = true;
bool stderr_is_console = true;
//! True if an interrupt (Control-C) has been received.
atomic<idx_t> seenInterrupt;
//! Name of our program
const char *program_name;
//! Whether or not syntax highlighting is enabled
bool highlighting_enabled = true;
//! Whether or not we are running in safe mode
bool safe_mode = false;
//! Whether or not we are highlighting errors
OptionType highlight_errors = OptionType::DEFAULT;
//! Whether or not we are highlighting results
OptionType highlight_results = OptionType::DEFAULT;
//! Path to .duckdbrc file
string duckdb_rc_path;
//! Startup text to display
StartupText startup_text = StartupText::ALL;
//! Whether or not the loading resources message was displayed
bool displayed_loading_resources_message = false;
/*
** Prompt strings. Initialized in main. Settable with
** .prompt main continue
*/
static constexpr idx_t MAX_PROMPT_SIZE = 20;
unique_ptr<Prompt> main_prompt;
//! Continuation prompt
char continuePrompt[MAX_PROMPT_SIZE];
//! Selected continuation prompt
char continuePromptSelected[MAX_PROMPT_SIZE];
//! Prompt showing there is more text available up
char scrollUpPrompt[MAX_PROMPT_SIZE];
//! Prompt showing there is more text available down
char scrollDownPrompt[MAX_PROMPT_SIZE];
//! Progress bar used to render the components that are displayed when query status / progress is rendered
unique_ptr<ShellProgressBar> progress_bar;
//! User-configured highlight elements
duckdb::unordered_set<HighlightElementType> user_configured_elements;
#ifdef HAVE_LINENOISE
ReadLineVersion rl_version = ReadLineVersion::LINENOISE;
#else
ReadLineVersion rl_version = ReadLineVersion::FALLBACK;
#endif
//! Whether or not to run the pager
PagerMode pager_mode = PagerMode::PAGER_AUTOMATIC;
//! The command to run when running the pager
string pager_command;
// In automatic mode, only show a pager when this row count is exceeded
idx_t pager_min_rows = 50;
//! Whether or not the pager is currently active
bool pager_is_active = false;
//! Shell highlighting mode
HighlightMode highlight_mode = HighlightMode::AUTOMATIC;
public:
ShellState();
~ShellState();
static ShellState &Get();
static ShellState *&GetReference();
void Initialize();
void Destroy();
void PushOutputMode();
void PopOutputMode();
void OutputCSV(const char *z, int bSep);
string EscapeCString(const string &z);
string GetSchemaLine(const string &str, const string &tail);
string GetSchemaLineN(const string &str, idx_t n, const string &tail);
bool SetOutputMode(const string &mode, const char *tbl_name);
bool ImportData(const vector<string> &args);
bool OpenDatabase(const vector<string> &args);
bool SetOutputFile(const vector<string> &args, char output_mode);
bool ReadFromFile(const string &file);
bool DisplaySchemas(const vector<string> &args);
MetadataResult DisplayEntries(const vector<string> &args, char type);
MetadataResult DisplayTables(const vector<string> &args);
void ShowConfiguration();
void ClearInterrupt();
static void Exit(int exit_code);
static idx_t RenderLength(const char *str, idx_t str_len);
static idx_t RenderLength(duckdb::string_t str);
static idx_t RenderLength(const string &str);
static bool IsCharacter(char c);
void SetBinaryMode();
void SetTextMode();
static idx_t StringLength(const char *z);
void SetTableName(const char *zName);
static void StaticPrint(PrintOutput output, const char *str, idx_t len);
void Print(PrintOutput output, const char *str, idx_t len);
void Print(PrintOutput output, const char *str);
void Print(PrintOutput output, duckdb::string_t str);
void Print(PrintOutput output, const string &str);
void Print(const char *str, idx_t len);
void Print(duckdb::string_t str);
void Print(const char *str);
void Print(const string &str);
template <typename... ARGS>
void PrintF(PrintOutput stream, const string &str, ARGS... params) {
Print(stream, StringUtil::Format(str, params...));
}
template <typename... ARGS>
void PrintF(const string &str, ARGS... params) {
PrintF(PrintOutput::STDOUT, str, std::forward<ARGS>(params)...);
}
bool ColumnTypeIsInteger(const char *type);
unique_ptr<ShellRenderer> GetRenderer();
unique_ptr<ShellRenderer> GetRenderer(RenderMode mode);
vector<string> TableColumnList(const char *zTab);
SuccessState ExecuteStatement(unique_ptr<duckdb::SQLStatement> statement);
static bool UseDescribeRenderMode(const duckdb::SQLStatement &stmt, string &describe_table_name);
void RenderTableMetadata(vector<ShellTableInfo> &result);
void PrintDatabaseError(const string &zErr);
int RunInitialCommand(const char *sql, bool bail);
void AddError();
SuccessState ExecuteSQL(const string &zSql);
void RunSchemaDumpQuery(const string &zQuery);
void RunTableDumpQuery(const string &zSelect);
void OpenDB(ShellOpenFlags open_flags = ShellOpenFlags::EXIT_ON_FAILURE);
void SetOrClearFlag(ShellFlags mFlag, const string &zArg);
bool ShellHasFlag(ShellFlags flag) {
return (shellFlgs & static_cast<uint32_t>(flag)) != 0;
}
void ShellSetFlag(ShellFlags flag) {
shellFlgs |= static_cast<uint32_t>(flag);
}
void ShellClearFlag(ShellFlags flag) {
shellFlgs &= ~static_cast<uint32_t>(flag);
}
void ResetOutput();
bool ShouldUsePager(ShellRenderer &renderer, RenderingQueryResult &result);
bool ShouldUsePager();
bool ShouldUsePager(idx_t line_count);
idx_t GetMaxRenderWidth() const;
string GetSystemPager();
unique_ptr<PagerState> SetupPager();
static void StartPagerDisplay();
static void FinishPagerDisplay();
void ClearTempFile();
void NewTempFile(const char *zSuffix);
int DoMetaCommand(const string &zLine);
idx_t PrintHelp(const char *zPattern);
void ShellAddHistory(const char *line);
int ShellLoadHistory(const char *path);
int ShellSaveHistory(const char *path);
int ShellSetHistoryMaxLength(idx_t max_length);
char *OneInputLine(FILE *in, char *zPrior, int isContinuation);
int RunOneSqlLine(InputMode mode, char *zSql);
string GetDefaultDuckDBRC();
bool ProcessDuckDBRC(const char *file);
bool ProcessFile(const string &file, InputMode input_mode = InputMode::FILE, bool default_duckdb_rc = false);
int ProcessInput(InputMode mode);
bool GetBailOnError(InputMode mode);
static bool SQLIsComplete(const char *zSql);
static bool IsSpace(char c);
static bool IsDigit(char c);
static int64_t StringToInt(const string &arg);
bool StringToBool(const string &zArg);
static void GenerateRandomBytes(int N, void *pBuf);
static bool StringGlob(const char *zGlobPattern, const char *zString);
static bool StringLike(const char *zPattern, const char *zStr, unsigned int esc);
static void Sleep(idx_t ms);
void PrintUsage();
void DetectDarkLightMode();
#if defined(_WIN32) || defined(WIN32)
static std::wstring Win32Utf8ToUnicode(const string &zText);
static std::wstring Win32Utf8ToUnicode(const char *) = delete;
static std::wstring Win32Utf8ToUnicode(char *) = delete;
static string Win32UnicodeToUtf8(const std::wstring &zWideText);
static string Win32MbcsToUtf8(const string &zText, bool useAnsi);
static string Win32Utf8ToMbcs(const string &zText, bool useAnsi);
#endif
optional_ptr<const CommandLineOption> FindCommandLineOption(const string &option, string &error_msg) const;
optional_ptr<const MetadataCommand> FindMetadataCommand(const string &option, string &error_msg) const;
static vector<string> GetMetadataCompletions(const char *zLine, idx_t nLine);
//! Execute a SQL query
// On fail - print the error and returns FAILURE
SuccessState ExecuteQuery(const string &query);
//! Execute a SQL query and extracts a single string value
ExecuteSQLSingleValueResult ExecuteSQLSingleValue(const string &sql, string &result);
ExecuteSQLSingleValueResult ExecuteSQLSingleValue(duckdb::Connection &con, const string &sql, string &result_value);
//! Execute a SQL query and renders the result using the given renderer.
//! On fail - prints the error and returns FAILURE
SuccessState RenderQuery(ShellRenderer &renderer, const string &query, PagerMode pager_overwrite);
SuccessState RenderQueryResult(ShellRenderer &renderer, duckdb::QueryResult &result,
PagerMode pager_overwrite = PagerMode::PAGER_AUTOMATIC);
bool HighlightErrors() const;
bool HighlightResults() const;
static MetadataResult SetNullValue(ShellState &state, const vector<string> &args);
static MetadataResult SetSeparator(ShellState &state, const vector<string> &args);
static MetadataResult EnableSafeMode(ShellState &state, const vector<string> &args);
static MetadataResult ToggleTimer(ShellState &state, const vector<string> &args);
SuccessState ChangeDirectory(const string &path);
SuccessState ShowDatabases();
void CloseOutputFile(FILE *file);
FILE *OpenOutputFile(const char *zFile, int bTextMode);
static void SetPrompt(char prompt[], const string &new_value);
static string ModeToString(RenderMode mode);
};
struct PagerState {
explicit PagerState(ShellState &state, uint32_t win_console_cp_before_pager_p = 0)
: state(state), win_console_cp_before_pager(win_console_cp_before_pager_p) {
}
~PagerState();
optional_ptr<ShellState> state;
uint32_t win_console_cp_before_pager = 0;
};
} // namespace duckdb_shell
|