1
1
mirror of https://github.com/tstack/lnav.git synced 2024-09-11 13:05:51 +03:00

[cleanup] move some code around and try to pretty things up a bit

This commit is contained in:
Timothy Stack 2013-06-06 07:01:32 -07:00
parent 178937886c
commit 5ba3097ee7
29 changed files with 1091 additions and 516 deletions

View File

@ -46,6 +46,7 @@ noinst_HEADERS = \
listview_curses.hh \
lnav.hh \
lnav_commands.hh \
lnav_config.hh \
lnav_util.hh \
log_data_table.hh \
log_format.hh \
@ -57,6 +58,8 @@ noinst_HEADERS = \
sequence_matcher.hh \
sequence_sink.hh \
session_data.hh \
sql_util.hh \
sqlite-extension-func.h \
status_controllers.hh \
statusview_curses.hh \
strnatcmp.h \
@ -95,6 +98,7 @@ libdiag_a_SOURCES = \
line_buffer.cc \
listview_curses.cc \
lnav_commands.cc \
lnav_config.cc \
lnav_util.cc \
log_format.cc \
logfile.cc \
@ -105,8 +109,10 @@ libdiag_a_SOURCES = \
readline_curses.cc \
session_data.cc \
sequence_matcher.cc \
sqlite-extension-func.c \
statusview_curses.cc \
piper_proc.cc \
sql_util.cc \
strnatcmp.c \
textview_curses.cc \
view_curses.cc \

View File

@ -110,19 +110,19 @@ am_libdiag_a_OBJECTS = bookmarks.$(OBJEXT) \
fs-extension-functions.$(OBJEXT) grep_proc.$(OBJEXT) \
hist_source.$(OBJEXT) line_buffer.$(OBJEXT) \
listview_curses.$(OBJEXT) lnav_commands.$(OBJEXT) \
lnav_util.$(OBJEXT) log_format.$(OBJEXT) logfile.$(OBJEXT) \
logfile_sub_source.$(OBJEXT) \
lnav_config.$(OBJEXT) lnav_util.$(OBJEXT) log_format.$(OBJEXT) \
logfile.$(OBJEXT) logfile_sub_source.$(OBJEXT) \
network-extension-functions.$(OBJEXT) data_scanner.$(OBJEXT) \
data_parser.$(OBJEXT) readline_curses.$(OBJEXT) \
session_data.$(OBJEXT) sequence_matcher.$(OBJEXT) \
statusview_curses.$(OBJEXT) piper_proc.$(OBJEXT) \
strnatcmp.$(OBJEXT) textview_curses.$(OBJEXT) \
view_curses.$(OBJEXT) vt52_curses.$(OBJEXT) \
log_vtab_impl.$(OBJEXT) xterm_mouse.$(OBJEXT) yajlpp.$(OBJEXT) \
yajl.$(OBJEXT) yajl_alloc.$(OBJEXT) yajl_buf.$(OBJEXT) \
yajl_encode.$(OBJEXT) yajl_gen.$(OBJEXT) yajl_lex.$(OBJEXT) \
yajl_parser.$(OBJEXT) yajl_tree.$(OBJEXT) \
yajl_version.$(OBJEXT)
sqlite-extension-func.$(OBJEXT) statusview_curses.$(OBJEXT) \
piper_proc.$(OBJEXT) sql_util.$(OBJEXT) strnatcmp.$(OBJEXT) \
textview_curses.$(OBJEXT) view_curses.$(OBJEXT) \
vt52_curses.$(OBJEXT) log_vtab_impl.$(OBJEXT) \
xterm_mouse.$(OBJEXT) yajlpp.$(OBJEXT) yajl.$(OBJEXT) \
yajl_alloc.$(OBJEXT) yajl_buf.$(OBJEXT) yajl_encode.$(OBJEXT) \
yajl_gen.$(OBJEXT) yajl_lex.$(OBJEXT) yajl_parser.$(OBJEXT) \
yajl_tree.$(OBJEXT) yajl_version.$(OBJEXT)
libdiag_a_OBJECTS = $(am_libdiag_a_OBJECTS)
am__installdirs = "$(DESTDIR)$(bindir)"
PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
@ -363,6 +363,7 @@ noinst_HEADERS = \
listview_curses.hh \
lnav.hh \
lnav_commands.hh \
lnav_config.hh \
lnav_util.hh \
log_data_table.hh \
log_format.hh \
@ -374,6 +375,8 @@ noinst_HEADERS = \
sequence_matcher.hh \
sequence_sink.hh \
session_data.hh \
sql_util.hh \
sqlite-extension-func.h \
status_controllers.hh \
statusview_curses.hh \
strnatcmp.h \
@ -412,6 +415,7 @@ libdiag_a_SOURCES = \
line_buffer.cc \
listview_curses.cc \
lnav_commands.cc \
lnav_config.cc \
lnav_util.cc \
log_format.cc \
logfile.cc \
@ -422,8 +426,10 @@ libdiag_a_SOURCES = \
readline_curses.cc \
session_data.cc \
sequence_matcher.cc \
sqlite-extension-func.c \
statusview_curses.cc \
piper_proc.cc \
sql_util.cc \
strnatcmp.c \
textview_curses.cc \
view_curses.cc \
@ -582,6 +588,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listview_curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnav.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnav_commands.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnav_config.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lnav_util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_format.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log_vtab_impl.Po@am__quote@
@ -592,6 +599,8 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/readline_curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sequence_matcher.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/session_data.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sql_util.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sqlite-extension-func.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statusview_curses.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strnatcmp.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/textview_curses.Po@am__quote@

View File

@ -123,12 +123,14 @@ public:
const T *operator->(void) const { return &this->srm_value; };
operator T(void) { return this->srm_value; };
T in(void) { return this->srm_value; };
const T &in(void) const { return this->srm_value; };
T *inout(void) { return &this->srm_value; };
private:
static_root_mem &operator =(T &) { return *this; };
static_root_mem &operator =(static_root_mem &) { return *this; };
T srm_value;
};
#endif

View File

@ -1,5 +1,5 @@
/**
* Copyright (c) 2007-2012, Timothy Stack
* Copyright (c) 2007-2013, Timothy Stack
*
* All rights reserved.
*
@ -31,6 +31,7 @@
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <sys/types.h>
#include <string>
@ -55,6 +56,8 @@ struct byte_array {
};
void to_string(char *buffer) const {
assert(buffer != NULL);
for (size_t lpc = 0; lpc < BYTE_COUNT; lpc++) {
snprintf(&buffer[lpc * 2], 3, "%02x", this->ba_data[lpc]);
}
@ -67,6 +70,7 @@ struct byte_array {
return std::string(buffer);
}
const unsigned char *in() const { return this->ba_data; };
unsigned char *out() { return this->ba_data; };
unsigned char ba_data[BYTE_COUNT];

View File

@ -155,7 +155,7 @@ int sql_strnatcasecmp(void *ptr,
int register_collation_functions(sqlite3 *db)
{
sqlite3_create_collation(db, "ipaddress", SQLITE_UTF8, NULL, ipaddress);
sqlite3_create_collation(db, "natural", SQLITE_UTF8, NULL, sql_strnatcmp);
sqlite3_create_collation(db, "naturalcase", SQLITE_UTF8, NULL, sql_strnatcmp);
sqlite3_create_collation(db, "naturalnocase", SQLITE_UTF8, NULL,
sql_strnatcasecmp);

View File

@ -44,7 +44,7 @@ public:
this->cn_builtin_names.push_back("col");
};
bool existing_name(const std::string &in_name)
bool existing_name(const std::string &in_name) const
{
if (find(this->cn_builtin_names.begin(),
this->cn_builtin_names.end(),

View File

@ -153,7 +153,7 @@ public:
static data_format FORMAT_COMMA;
static data_format FORMAT_PLAIN;
typedef byte_array<20> schema_id_t;
typedef byte_array<SHA_DIGEST_LENGTH> schema_id_t;
struct element;
typedef std::list<element> element_list_t;
@ -223,14 +223,24 @@ public:
}
};
const element &get_pair_value(void) const {
assert(this->e_token == DNT_PAIR);
return this->e_sub_elements->back();
};
data_token_t value_token(void) const
{
data_token_t retval = DT_INVALID;
if (this->e_token == DNT_VALUE &&
this->e_sub_elements != NULL &&
this->e_sub_elements->size() == 1) {
retval = this->e_sub_elements->front().e_token;
if (this->e_token == DNT_VALUE) {
if (this->e_sub_elements != NULL &&
this->e_sub_elements->size() == 1) {
retval = this->e_sub_elements->front().e_token;
}
}
else {
retval = this->e_token;
}
return retval;
};
@ -692,7 +702,7 @@ private:
}
};
std::string get_element_string(element &elem)
std::string get_element_string(const element &elem)
{
pcre_input &pi = this->dp_scanner->get_input();

View File

@ -143,6 +143,8 @@ SQLITE_EXTENSION_INIT1
#include <stdint.h>
#include <inttypes.h>
#include "sqlite-extension-func.h"
/*
** Simple binary tree implementation to use in median, mode and quartile calculations
** Tree is not necessarily balanced. That would require something like red&black trees of AVL
@ -1704,15 +1706,9 @@ static void differenceFunc(sqlite3_context *context, int argc, sqlite3_value **a
** functions. This should be the only routine in this file with
** external linkage.
*/
int RegisterExtensionFunctions(sqlite3 *db){
static const struct FuncDef {
char *zName;
signed char nArg;
u8 argType; /* 0: none. 1: db 2: (-1) */
u8 eTextRep; /* 1: UTF-16. 0: UTF-8 */
u8 needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
} aFuncs[] = {
int common_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs) {
static const struct FuncDef aFuncs[] = {
/* math.h */
{ "acos", 1, 0, SQLITE_UTF8, 0, acosFunc },
{ "asin", 1, 0, SQLITE_UTF8, 0, asinFunc },
@ -1770,16 +1766,11 @@ int RegisterExtensionFunctions(sqlite3 *db){
{ "padc", 2, 0, SQLITE_UTF8, 0, padcFunc },
{ "strfilter", 2, 0, SQLITE_UTF8, 0, strfilterFunc },
{ NULL }
};
/* Aggregate functions */
static const struct FuncDefAgg {
char *zName;
signed char nArg;
u8 argType;
u8 needCollSeq;
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
void (*xFinalize)(sqlite3_context*);
} aAggs[] = {
static const struct FuncDefAgg aAggs[] = {
{ "stdev", 1, 0, 0, varianceStep, stdevFinalize },
{ "stddev", 1, 0, 0, varianceStep, stdevFinalize },
{ "variance", 1, 0, 0, varianceStep, varianceFinalize },
@ -1787,51 +1778,14 @@ int RegisterExtensionFunctions(sqlite3 *db){
{ "median", 1, 0, 0, modeStep, medianFinalize },
{ "lower_quartile", 1, 0, 0, modeStep, lower_quartileFinalize },
{ "upper_quartile", 1, 0, 0, modeStep, upper_quartileFinalize },
{ NULL }
};
int i;
for(i=0; i<sizeof(aFuncs)/sizeof(aFuncs[0]); i++){
void *pArg = 0;
switch( aFuncs[i].argType ){
case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break;
}
//sqlite3CreateFunc
/* LMH no error checking */
sqlite3_create_function(db, aFuncs[i].zName, aFuncs[i].nArg,
aFuncs[i].eTextRep, pArg, aFuncs[i].xFunc, 0, 0);
#if 0
if( aFuncs[i].needCollSeq ){
struct FuncDef *pFunc = sqlite3FindFunction(db, aFuncs[i].zName,
strlen(aFuncs[i].zName), aFuncs[i].nArg, aFuncs[i].eTextRep, 0);
if( pFunc && aFuncs[i].needCollSeq ){
pFunc->needCollSeq = 1;
}
}
#endif
}
*basic_funcs = aFuncs;
*agg_funcs = aAggs;
for(i=0; i<sizeof(aAggs)/sizeof(aAggs[0]); i++){
void *pArg = 0;
switch( aAggs[i].argType ){
case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break;
}
//sqlite3CreateFunc
/* LMH no error checking */
sqlite3_create_function(db, aAggs[i].zName, aAggs[i].nArg, SQLITE_UTF8,
pArg, 0, aAggs[i].xStep, aAggs[i].xFinalize);
#if 0
if( aAggs[i].needCollSeq ){
struct FuncDefAgg *pFunc = sqlite3FindFunction( db, aAggs[i].zName,
strlen(aAggs[i].zName), aAggs[i].nArg, SQLITE_UTF8, 0);
if( pFunc && aAggs[i].needCollSeq ){
pFunc->needCollSeq = 1;
}
}
#endif
}
return 0;
return SQLITE_OK;
}
#ifdef COMPILE_SQLITE_EXTENSIONS_AS_LOADABLE_MODULE

View File

@ -38,6 +38,8 @@
#include "sqlite3.h"
#include "sqlite-extension-func.h"
static void sql_basename(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
@ -155,36 +157,19 @@ static void sql_joinpath(sqlite3_context *context,
sqlite3_result_text(context, full_path.c_str(), -1, SQLITE_TRANSIENT);
}
int register_fs_extension_functions(sqlite3 *db)
int fs_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs)
{
static const struct {
const char *name;
char narg;
uint8_t text_rep;
void (*func)(sqlite3_context *, int, sqlite3_value **);
} plain_funcs[] = {
{ "basename", 1, SQLITE_UTF8, sql_basename },
{ "dirname", 1, SQLITE_UTF8, sql_dirname },
{ "joinpath", -1, SQLITE_UTF8, sql_joinpath },
static const struct FuncDef fs_funcs[] = {
{ "basename", 1, 0, SQLITE_UTF8, 0, sql_basename },
{ "dirname", 1, 0, SQLITE_UTF8, 0, sql_dirname },
{ "joinpath", -1, 0, SQLITE_UTF8, 0, sql_joinpath },
{ NULL }
};
int retval;
for (int lpc = 0; plain_funcs[lpc].name; lpc++) {
retval = sqlite3_create_function(db,
plain_funcs[lpc].name,
plain_funcs[lpc].narg,
plain_funcs[lpc].text_rep,
NULL,
plain_funcs[lpc].func,
NULL,
NULL);
if (retval != SQLITE_OK) {
return retval;
}
}
*basic_funcs = fs_funcs;
*agg_funcs = NULL;
return SQLITE_OK;
}

View File

@ -97,6 +97,9 @@
#include "column_namer.hh"
#include "log_data_table.hh"
#include "session_data.hh"
#include "lnav_config.hh"
#include "sql_util.hh"
#include "sqlite-extension-func.h"
#include "yajlpp.hh"
@ -135,58 +138,6 @@ const char *lnav_view_strings[LNV__MAX] = {
"example",
};
/**
* Check if an experimental feature should be enabled by
* examining the LNAV_EXP environment variable.
*
* @param feature_name The feature name to check for in
* the LNAV_EXP environment variable.
*
* @return True if the feature was mentioned in the env
* var and should be enabled.
*/
bool check_experimental(const char *feature_name)
{
const char *env_value = getenv("LNAV_EXP");
if (env_value && strcasestr(env_value, feature_name)) {
return true;
}
return false;
}
/**
* Compute the path to a file in the user's '.lnav' directory.
*
* @param sub The path to the file in the '.lnav' directory.
* @return The full path
*/
string dotlnav_path(const char *sub)
{
string retval;
char * home;
home = getenv("HOME");
if (home) {
char hpath[2048];
snprintf(hpath, sizeof(hpath), "%s/.lnav/%s", home, sub);
retval = hpath;
}
else {
retval = sub;
}
return retval;
}
/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem)
{
sqlite3_close((sqlite3 *)mem);
}
class field_overlay_source : public list_overlay_source {
public:
field_overlay_source()
@ -360,15 +311,6 @@ public:
int fos_key_size;
};
typedef std::map<string, std::vector<string> > db_table_map_t;
class db_metadata {
public:
db_metadata() { };
db_table_map_t dm_db_list;
};
static int handle_collation_list(void *ptr,
int ncols,
char **colvalues,
@ -384,10 +326,6 @@ static int handle_db_list(void *ptr,
char **colvalues,
char **colnames)
{
db_metadata *dbm = (db_metadata *)ptr;
dbm->dm_db_list[colvalues[1]] = std::vector<string>();
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
return 0;
@ -398,12 +336,7 @@ static int handle_table_list(void *ptr,
char **colvalues,
char **colnames)
{
std::map<string,
std::vector<string> >::iterator iter =
*(std::map<string, std::vector<string> >::iterator *)ptr;
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[0]);
iter->second.push_back(colvalues[0]);
return 0;
}
@ -413,8 +346,6 @@ static int handle_table_info(void *ptr,
char **colvalues,
char **colnames)
{
/* string &table_name = *((string *)ptr); */
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", colvalues[1]);
if (strcmp(colvalues[5], "1") == 0) {
lnav_data.ld_db_key_names.push_back(colvalues[1]);
@ -432,155 +363,13 @@ static int handle_foreign_key_list(void *ptr,
return 0;
}
static void walk_sqlite_metadata(sqlite3 *db)
{
db_metadata dbm;
lnav_data.ld_db_key_names.clear();
lnav_data.ld_rl_view->clear_possibilities(LNM_SQL, "*");
{
const char *sql_commands[] = {
"ADD",
"ALL",
"ALTER",
"ANALYZE",
"AND",
"ASC",
"ATTACH",
"BEGIN",
"BETWEEN",
"CASE",
"CAST",
"COLLATE",
"COLUMN",
"COMMIT",
"CONFLICT",
"CREATE",
"CROSS",
"DATABASE",
"DELETE",
"DESC",
"DETACH",
"DISTINCT",
"DROP",
"ELSE",
"END",
"ESCAPE",
"EXCEPT",
"EXISTS",
"EXPLAIN",
"FROM",
"GLOB",
"GROUP",
"HAVING",
"IN",
"INDEX",
"INDEXED",
"INNER",
"INSERT",
"INTERSECT",
"ISNULL",
"JOIN",
"LEFT",
"LIKE",
"LIMIT",
"MATCH",
"NATURAL",
"NOT",
"NOTNULL",
"NULL",
"OFFSET",
"OR",
"ORDER",
"OUTER",
"PRAGMA",
"REGEXP",
"REINDEX",
"RENAME",
"REPLACE",
"ROLLBACK",
"SELECT",
"TABLE",
"THEN",
"TRANSACTION",
"TRIGGER",
"UNION",
"UNIQUE",
"UPDATE",
"USING",
"VACUUM",
"VIEW",
"WHERE",
"WHEN",
"logline",
NULL
};
for (int lpc = 0; sql_commands[lpc]; lpc++) {
lnav_data.ld_rl_view->
add_possibility(LNM_SQL, "*", sql_commands[lpc]);
}
}
sqlite3_exec(db,
"pragma collation_list",
handle_collation_list,
NULL,
NULL);
sqlite3_exec(db,
"pragma database_list",
handle_db_list,
&dbm,
NULL);
for (db_table_map_t::iterator iter = dbm.dm_db_list.begin();
iter != dbm.dm_db_list.end();
++iter) {
auto_mem<char, sqlite3_free> query;
query = sqlite3_mprintf("SELECT name FROM %Q.sqlite_master "
"WHERE type='table'",
iter->first.c_str());
sqlite3_exec(db, query, handle_table_list, &iter, NULL);
for (std::vector<string>::iterator table_iter = iter->second.begin();
table_iter != iter->second.end();
++table_iter) {
auto_mem<char, sqlite3_free> table_query;
string &table_name = *table_iter;
table_query = sqlite3_mprintf(
"pragma %Q.table_info(%Q)",
iter->first.c_str(),
table_name.c_str());
sqlite3_exec(db,
table_query,
handle_table_info,
&table_name,
NULL);
table_query = sqlite3_mprintf(
"pragma %Q.foreign_key_list(%Q)",
iter->first.c_str(),
table_name.c_str());
sqlite3_exec(db,
table_query,
handle_foreign_key_list,
&table_name,
NULL);
}
}
stable_sort(lnav_data.ld_db_key_names.begin(),
lnav_data.ld_db_key_names.end());
}
struct sqlite_metadata_callbacks lnav_sql_meta_callbacks = {
handle_collation_list,
handle_db_list,
handle_table_list,
handle_table_info,
handle_foreign_key_list,
};
bool setup_logline_table()
{
@ -597,7 +386,16 @@ bool setup_logline_table()
retval = true;
}
walk_sqlite_metadata(lnav_data.ld_db.in());
lnav_data.ld_db_key_names.clear();
lnav_data.ld_rl_view->clear_possibilities(LNM_SQL, "*");
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", sql_keywords);
lnav_data.ld_rl_view->add_possibility(LNM_SQL, "*", sql_function_names);
walk_sqlite_metadata(lnav_data.ld_db.in(), lnav_sql_meta_callbacks);
stable_sort(lnav_data.ld_db_key_names.begin(),
lnav_data.ld_db_key_names.end());
return retval;
}
@ -886,45 +684,6 @@ public:
};
};
static string get_current_dir(void)
{
char cwd[FILENAME_MAX];
string retval = ".";
if (getcwd(cwd, sizeof(cwd)) == NULL) {
perror("getcwd");
}
else {
retval = string(cwd);
}
if (retval != "/") {
retval += "/";
}
return retval;
}
static bool change_to_parent_dir(void)
{
bool retval = false;
char cwd[3] = "";
if (getcwd(cwd, sizeof(cwd)) == NULL) {
/* perror("getcwd"); */
}
if (strcmp(cwd, "/") != 0) {
if (chdir("..") == -1) {
perror("chdir('..')");
}
else {
retval = true;
}
}
return retval;
}
static bool append_default_files(lnav_flags_t flag)
{
bool retval = true;
@ -2268,73 +2027,6 @@ static void update_times(void *, listview_curses *lv)
}
}
enum file_format_t {
FF_UNKNOWN,
FF_SQLITE_DB,
};
file_format_t detect_file_format(const string &filename)
{
file_format_t retval = FF_UNKNOWN;
int fd;
if ((fd = open(filename.c_str(), O_RDONLY)) != -1) {
char buffer[32];
int rc;
if ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
if (rc > 16 &&
strncmp(buffer, "SQLite format 3", 16) == 0) {
retval = FF_SQLITE_DB;
}
}
}
return retval;
}
void attach_sqlite_db(const string &filename)
{
static pcrecpp::RE db_name_converter("[^\\w]");
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
if (sqlite3_prepare_v2(lnav_data.ld_db.in(),
"ATTACH DATABASE ? as ?",
-1,
stmt.out(),
NULL) != SQLITE_OK) {
return;
}
if (sqlite3_bind_text(stmt.in(), 1,
filename.c_str(), filename.length(),
SQLITE_TRANSIENT) != SQLITE_OK) {
return;
}
size_t base_start = filename.find_last_of("/\\");
string db_name;
if (base_start == string::npos) {
db_name = filename;
}
else {
db_name = filename.substr(base_start + 1);
}
db_name_converter.GlobalReplace("_", &db_name);
if (sqlite3_bind_text(stmt.in(), 2,
db_name.c_str(), db_name.length(),
SQLITE_TRANSIENT) != SQLITE_OK) {
return;
}
sqlite3_step(stmt.in());
}
/**
* Functor used to compare files based on their device and inode number.
*/
@ -2411,7 +2103,7 @@ static void watch_logfile(string filename, int fd, bool required)
switch (ff) {
case FF_SQLITE_DB:
lnav_data.ld_other_files.push_back(filename);
attach_sqlite_db(filename);
attach_sqlite_db(lnav_data.ld_db.in(), filename);
break;
default:
@ -3182,15 +2874,6 @@ private:
#endif
};
void ensure_dotlnav(void)
{
string path = dotlnav_path("");
if (!path.empty()) {
mkdir(path.c_str(), 0755);
}
}
static void setup_highlights(textview_curses::highlight_map_t &hm)
{
hm["$sql"] = textview_curses::
@ -3230,13 +2913,6 @@ static void setup_highlights(textview_curses::highlight_map_t &hm)
"^#\\s*(?:if|ifndef|ifdef|else|define|undef|endif)\\b"));
}
extern "C" {
int RegisterExtensionFunctions(sqlite3 *db);
}
int register_network_extension_functions(sqlite3 *db);
int register_fs_extension_functions(sqlite3 *db);
int sql_progress(const struct log_cursor &lc)
{
size_t total = lnav_data.ld_log_source.text_line_count();
@ -3284,9 +2960,7 @@ int main(int argc, char *argv[])
{
int register_collation_functions(sqlite3 * db);
RegisterExtensionFunctions(lnav_data.ld_db.in());
register_network_extension_functions(lnav_data.ld_db.in());
register_fs_extension_functions(lnav_data.ld_db.in());
register_sqlite_funcs(lnav_data.ld_db.in(), sqlite_registration_funcs);
register_collation_functions(lnav_data.ld_db.in());
}

View File

@ -179,8 +179,6 @@ extern struct _lnav_data lnav_data;
void rebuild_indexes(bool force);
std::string dotlnav_path(const char *sub);
void ensure_view(textview_curses *expected_tc);
bool toggle_view(textview_curses *toggle_tc);

View File

@ -38,6 +38,7 @@
#include <pcrecpp.h>
#include "lnav.hh"
#include "lnav_config.hh"
#include "lnav_util.hh"
#include "auto_mem.hh"
#include "log_data_table.hh"

80
src/lnav_config.cc Normal file
View File

@ -0,0 +1,80 @@
/**
* Copyright (c) 2013, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file lnav_config.cc
*/
#include "config.h"
#include <assert.h>
#include <sys/stat.h>
#include "lnav_config.hh"
using namespace std;
string dotlnav_path(const char *sub)
{
string retval;
char * home;
home = getenv("HOME");
if (home) {
char hpath[PATH_MAX];
snprintf(hpath, sizeof(hpath), "%s/.lnav/%s", home, sub);
retval = hpath;
}
else {
retval = sub;
}
return retval;
}
bool check_experimental(const char *feature_name)
{
const char *env_value = getenv("LNAV_EXP");
assert(feature_name != NULL);
if (env_value && strcasestr(env_value, feature_name)) {
return true;
}
return false;
}
void ensure_dotlnav(void)
{
string path = dotlnav_path("");
if (!path.empty()) {
mkdir(path.c_str(), 0755);
}
}

62
src/lnav_config.hh Normal file
View File

@ -0,0 +1,62 @@
/**
* Copyright (c) 2013, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file lnav_config.hh
*/
#ifndef _lnav_config_hh
#define _lnav_config_hh
#include <string>
/**
* Compute the path to a file in the user's '.lnav' directory.
*
* @param sub The path to the file in the '.lnav' directory.
* @return The full path
*/
std::string dotlnav_path(const char *sub);
/**
* Check if an experimental feature should be enabled by
* examining the LNAV_EXP environment variable.
*
* @param feature_name The feature name to check for in
* the LNAV_EXP environment variable.
*
* @return True if the feature was mentioned in the env
* var and should be enabled.
*/
bool check_experimental(const char *feature_name);
/**
* Ensure that the '.lnav' directory exists.
*/
void ensure_dotlnav(void);
#endif

View File

@ -34,12 +34,15 @@
#include "config.h"
#include <stdio.h>
#include <fcntl.h>
#include <sqlite3.h>
#include "lnav_util.hh"
std::string hash_string(const std::string &str)
{
byte_array<20> hash;
byte_array<SHA_DIGEST_LENGTH> hash;
SHA_CTX context;
SHA_Init(&context);
@ -92,3 +95,68 @@ std::string time_ago(time_t last_time)
return std::string(buffer);
}
/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem)
{
sqlite3_close((sqlite3 *)mem);
}
std::string get_current_dir(void)
{
char cwd[FILENAME_MAX];
std::string retval = ".";
if (getcwd(cwd, sizeof(cwd)) == NULL) {
perror("getcwd");
}
else {
retval = std::string(cwd);
}
if (retval != "/") {
retval += "/";
}
return retval;
}
bool change_to_parent_dir(void)
{
bool retval = false;
char cwd[3] = "";
if (getcwd(cwd, sizeof(cwd)) == NULL) {
/* perror("getcwd"); */
}
if (strcmp(cwd, "/") != 0) {
if (chdir("..") == -1) {
perror("chdir('..')");
}
else {
retval = true;
}
}
return retval;
}
file_format_t detect_file_format(const std::string &filename)
{
file_format_t retval = FF_UNKNOWN;
int fd;
if ((fd = open(filename.c_str(), O_RDONLY)) != -1) {
char buffer[32];
int rc;
if ((rc = read(fd, buffer, sizeof(buffer))) > 0) {
if (rc > 16 &&
strncmp(buffer, "SQLite format 3", 16) == 0) {
retval = FF_SQLITE_DB;
}
}
}
return retval;
}

View File

@ -122,4 +122,18 @@ object_field_t<UnaryFunction, Member> object_field(UnaryFunction &func, Member m
return object_field_t<UnaryFunction, Member>(func, mem);
}
/* XXX figure out how to do this with the template */
void sqlite_close_wrapper(void *mem);
std::string get_current_dir(void);
bool change_to_parent_dir(void);
enum file_format_t {
FF_UNKNOWN,
FF_SQLITE_DB,
};
file_format_t detect_file_format(const std::string &filename);
#endif

View File

@ -172,19 +172,18 @@ public:
dp.dp_pairs.begin();
pair_iter != dp.dp_pairs.end();
++pair_iter) {
std::string tmp = dp.get_element_string(
pair_iter->e_sub_elements->back());
const data_parser::element &pvalue = pair_iter->get_pair_value();
std::string tmp = dp.get_element_string(pvalue);
fprintf(stderr, "data %s\n", tmp.c_str());
switch(pair_iter->e_sub_elements->back().e_token) {
case DT_NUMBER: {
switch(pvalue.value_token()) {
case DT_NUMBER: {
double d = 0;
sscanf(tmp.c_str(), "%lf", &d);
values.push_back(logline_value("", d));
}
break;
default:
default:
values.push_back(logline_value("", tmp));
break;
}

View File

@ -41,6 +41,8 @@
#include "sqlite3.h"
#include "sqlite-extension-func.h"
static void sql_gethostbyname(sqlite3_context *context,
int argc, sqlite3_value **argv)
{
@ -138,35 +140,17 @@ static void sql_gethostbyaddr(sqlite3_context *context,
sqlite3_result_text(context, buffer, -1, SQLITE_TRANSIENT);
}
int register_network_extension_functions(sqlite3 *db)
int network_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs)
{
static const struct {
const char *name;
char narg;
uint8_t text_rep;
void (*func)(sqlite3_context *, int, sqlite3_value **);
} plain_funcs[] = {
{ "gethostbyname", 1, SQLITE_UTF8, sql_gethostbyname },
{ "gethostbyaddr", 1, SQLITE_UTF8, sql_gethostbyaddr },
static const struct FuncDef network_funcs[] = {
{ "gethostbyname", 1, 0, SQLITE_UTF8, 0, sql_gethostbyname },
{ "gethostbyaddr", 1, 0, SQLITE_UTF8, 0, sql_gethostbyaddr },
{ NULL }
};
int retval;
for (int lpc = 0; plain_funcs[lpc].name; lpc++) {
retval = sqlite3_create_function(db,
plain_funcs[lpc].name,
plain_funcs[lpc].narg,
plain_funcs[lpc].text_rep,
NULL,
plain_funcs[lpc].func,
NULL,
NULL);
if (retval != SQLITE_OK) {
return retval;
}
}
*basic_funcs = network_funcs;
return SQLITE_OK;
}

View File

@ -580,7 +580,9 @@ void readline_curses::focus(int context, const char *prompt)
wclrtoeol(this->vc_window);
}
void readline_curses::add_possibility(int context, string type, string value)
void readline_curses::add_possibility(int context,
const string &type,
const string &value)
{
char buffer[1024];
@ -595,7 +597,9 @@ void readline_curses::add_possibility(int context, string type, string value)
}
}
void readline_curses::rem_possibility(int context, string type, string value)
void readline_curses::rem_possibility(int context,
const string &type,
const string &value)
{
char buffer[1024];

View File

@ -237,8 +237,21 @@ public:
void line_ready(const char *line);
void add_possibility(int context, std::string type, std::string value);
void rem_possibility(int context, std::string type, std::string value);
void add_possibility(int context,
const std::string &type,
const std::string &value);
void add_possibility(int context,
const std::string &type,
const char *values[]) {
for (int lpc = 0; values[lpc]; lpc++) {
this->add_possibility(context, type, values[lpc]);
}
};
void rem_possibility(int context,
const std::string &type,
const std::string &value);
void clear_possibilities(int context, std::string type);
private:

View File

@ -45,6 +45,7 @@
#include "lnav.hh"
#include "logfile.hh"
#include "lnav_util.hh"
#include "lnav_config.hh"
#include "session_data.hh"
using namespace std;
@ -54,16 +55,13 @@ static const size_t MAX_SESSIONS = 16;
static string bookmark_file_name(const string &name)
{
char mark_base_name[256];
SHA_CTX context;
byte_array<20> hash;
string hash;
SHA_Init(&context);
SHA_Update(&context, name.c_str(), name.length());
SHA_Final(hash.out(), &context);
hash = hash_string(name);
snprintf(mark_base_name, sizeof(mark_base_name),
"file-%s.ts%ld.json",
hash.to_string().c_str(),
hash.c_str(),
lnav_data.ld_session_time);
return string(mark_base_name);
@ -75,16 +73,13 @@ static string latest_bookmark_file(const string &name)
static_root_mem<glob_t, globfree> file_list;
string mark_file_pattern;
char mark_base_name[256];
SHA_CTX context;
byte_array<20> hash;
string hash;
SHA_Init(&context);
SHA_Update(&context, name.c_str(), name.length());
SHA_Final(hash.out(), &context);
hash = hash_string(name);
snprintf(mark_base_name, sizeof(mark_base_name),
"file-%s.ts*.json",
hash.to_string().c_str());
hash.c_str());
mark_file_pattern = dotlnav_path(mark_base_name);
@ -111,7 +106,7 @@ static string latest_bookmark_file(const string &name)
void init_session(void)
{
byte_array<20> hash;
byte_array<SHA_DIGEST_LENGTH> hash;
SHA_CTX context;
lnav_data.ld_session_time = time(NULL);

405
src/sql_util.cc Normal file
View File

@ -0,0 +1,405 @@
/**
* Copyright (c) 2013, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file sql_util.cc
*/
#include "config.h"
#include <stdio.h>
#include <pcrecpp.h>
#include "auto_mem.hh"
#include "sql_util.hh"
/**
* Copied from -- http://www.sqlite.org/lang_keywords.html
*/
const char *sql_keywords[] = {
"ABORT",
"ACTION",
"ADD",
"AFTER",
"ALL",
"ALTER",
"ANALYZE",
"AND",
"AS",
"ASC",
"ATTACH",
"AUTOINCREMENT",
"BEFORE",
"BEGIN",
"BETWEEN",
"BY",
"CASCADE",
"CASE",
"CAST",
"CHECK",
"COLLATE",
"COLUMN",
"COMMIT",
"CONFLICT",
"CONSTRAINT",
"CREATE",
"CROSS",
"CURRENT_DATE",
"CURRENT_TIME",
"CURRENT_TIMESTAMP",
"DATABASE",
"DEFAULT",
"DEFERRABLE",
"DEFERRED",
"DELETE",
"DESC",
"DETACH",
"DISTINCT",
"DROP",
"EACH",
"ELSE",
"END",
"ESCAPE",
"EXCEPT",
"EXCLUSIVE",
"EXISTS",
"EXPLAIN",
"FAIL",
"FOR",
"FOREIGN",
"FROM",
"FULL",
"GLOB",
"GROUP",
"HAVING",
"IF",
"IGNORE",
"IMMEDIATE",
"IN",
"INDEX",
"INDEXED",
"INITIALLY",
"INNER",
"INSERT",
"INSTEAD",
"INTERSECT",
"INTO",
"IS",
"ISNULL",
"JOIN",
"KEY",
"LEFT",
"LIKE",
"LIMIT",
"MATCH",
"NATURAL",
"NO",
"NOT",
"NOTNULL",
"NULL",
"OF",
"OFFSET",
"ON",
"OR",
"ORDER",
"OUTER",
"PLAN",
"PRAGMA",
"PRIMARY",
"QUERY",
"RAISE",
"REFERENCES",
"REGEXP",
"REINDEX",
"RELEASE",
"RENAME",
"REPLACE",
"RESTRICT",
"RIGHT",
"ROLLBACK",
"ROW",
"SAVEPOINT",
"SELECT",
"SET",
"TABLE",
"TEMP",
"TEMPORARY",
"THEN",
"TO",
"TRANSACTION",
"TRIGGER",
"UNION",
"UNIQUE",
"UPDATE",
"USING",
"VACUUM",
"VALUES",
"VIEW",
"VIRTUAL",
"WHEN",
"WHERE",
NULL
};
const char *sql_function_names[] = {
// http://www.sqlite.org/lang_aggfunc.html
"avg",
"count",
"group_concat",
"max",
"min",
"sum",
"total",
// http://www.sqlite.org/lang_corefunc.html
"abs",
"changes",
"char",
"coalesce",
"glob",
"ifnull",
"instr",
"hex",
"last_insert_rowid",
"length",
"like",
"load_extension",
"lower",
"ltrim",
"nullif",
"quote",
"random",
"randomblob",
"replace",
"round",
"rtrim",
"soundex",
"sqlite_compileoption_get",
"sqlite_compileoption_used",
"sqlite_source_id",
"sqlite_version",
"substr",
"total_changes",
"trim",
"typeof",
"unicode",
"upper",
"zeroblob",
NULL
};
static int handle_db_list(void *ptr,
int ncols,
char **colvalues,
char **colnames)
{
struct sqlite_metadata_callbacks *smc;
smc = (struct sqlite_metadata_callbacks *)ptr;
smc->smc_db_list[colvalues[1]] = std::vector<std::string>();
return smc->smc_database_list(ptr, ncols, colvalues, colnames);
}
struct table_list_data {
struct sqlite_metadata_callbacks *tld_callbacks;
db_table_map_t::iterator *tld_iter;
};
static int handle_table_list(void *ptr,
int ncols,
char **colvalues,
char **colnames)
{
struct table_list_data *tld = (struct table_list_data *)ptr;
(*tld->tld_iter)->second.push_back(colvalues[0]);
return tld->tld_callbacks->smc_table_list(tld->tld_callbacks,
ncols,
colvalues,
colnames);
}
int walk_sqlite_metadata(sqlite3 *db, struct sqlite_metadata_callbacks &smc)
{
auto_mem<char, sqlite3_free> errmsg;
int retval;
retval = sqlite3_exec(db,
"pragma collation_list",
smc.smc_collation_list,
&smc,
errmsg.out());
if (retval != SQLITE_OK) {
fprintf(stderr,
"error: could not get collation list -- %s\n",
errmsg.in());
return retval;
}
retval = sqlite3_exec(db,
"pragma database_list",
handle_db_list,
&smc,
errmsg.out());
if (retval != SQLITE_OK) {
fprintf(stderr, "error: could not get DB list -- %s\n", errmsg.in());
return retval;
}
for (db_table_map_t::iterator iter = smc.smc_db_list.begin();
iter != smc.smc_db_list.end();
++iter) {
struct table_list_data tld = { &smc, &iter };
auto_mem<char, sqlite3_free> query;
query = sqlite3_mprintf("SELECT name FROM %Q.sqlite_master "
"WHERE type='table'",
iter->first.c_str());
retval = sqlite3_exec(db,
query,
handle_table_list,
&tld,
errmsg.out());
if (retval != SQLITE_OK) {
fprintf(stderr,
"error: could not get table list -- %s\n",
errmsg.in());
return retval;
}
for (db_table_list_t::iterator table_iter = iter->second.begin();
table_iter != iter->second.end();
++table_iter) {
auto_mem<char, sqlite3_free> table_query;
std::string &table_name = *table_iter;
table_query = sqlite3_mprintf(
"pragma %Q.table_info(%Q)",
iter->first.c_str(),
table_name.c_str());
if (table_query == NULL) {
return SQLITE_NOMEM;
}
retval = sqlite3_exec(db,
table_query,
smc.smc_table_info,
&table_name,
errmsg.out());
if (retval != SQLITE_OK) {
fprintf(stderr,
"error: could not get table info -- %s\n",
errmsg.in());
return retval;
}
table_query = sqlite3_mprintf(
"pragma %Q.foreign_key_list(%Q)",
iter->first.c_str(),
table_name.c_str());
if (table_query == NULL) {
return SQLITE_NOMEM;
}
retval = sqlite3_exec(db,
table_query,
smc.smc_foreign_key_list,
&table_name,
errmsg.out());
if (retval != SQLITE_OK) {
fprintf(stderr,
"error: could not get foreign key list -- %s\n",
errmsg.in());
return retval;
}
}
}
return retval;
}
void attach_sqlite_db(sqlite3 *db, const std::string &filename)
{
static pcrecpp::RE db_name_converter("[^\\w]");
auto_mem<sqlite3_stmt> stmt(sqlite3_finalize);
if (sqlite3_prepare_v2(db,
"ATTACH DATABASE ? as ?",
-1,
stmt.out(),
NULL) != SQLITE_OK) {
fprintf(stderr,
"error: could not prepare DB attach statement -- %s\n",
sqlite3_errmsg(db));
return;
}
if (sqlite3_bind_text(stmt.in(), 1,
filename.c_str(), filename.length(),
SQLITE_TRANSIENT) != SQLITE_OK) {
fprintf(stderr,
"error: could not bind DB attach statement -- %s\n",
sqlite3_errmsg(db));
return;
}
size_t base_start = filename.find_last_of("/\\");
string db_name;
if (base_start == string::npos) {
db_name = filename;
}
else {
db_name = filename.substr(base_start + 1);
}
db_name_converter.GlobalReplace("_", &db_name);
if (sqlite3_bind_text(stmt.in(), 2,
db_name.c_str(), db_name.length(),
SQLITE_TRANSIENT) != SQLITE_OK) {
fprintf(stderr,
"error: could not bind DB attach statement -- %s\n",
sqlite3_errmsg(db));
return;
}
if (sqlite3_step(stmt.in()) != SQLITE_OK) {
fprintf(stderr,
"error: could not execute DB attach statement -- %s\n",
sqlite3_errmsg(db));
return;
}
}

61
src/sql_util.hh Normal file
View File

@ -0,0 +1,61 @@
/**
* Copyright (c) 2013, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file sql_util.hh
*/
#ifndef _sql_util_hh
#define _sql_util_hh
#include <sqlite3.h>
#include <map>
#include <string>
#include <vector>
extern const char *sql_keywords[];
extern const char *sql_function_names[];
typedef int (*sqlite_exec_callback)(void *, int, char **, char **);
typedef std::vector<std::string> db_table_list_t;
typedef std::map<std::string, db_table_list_t> db_table_map_t;
struct sqlite_metadata_callbacks {
sqlite_exec_callback smc_collation_list;
sqlite_exec_callback smc_database_list;
sqlite_exec_callback smc_table_list;
sqlite_exec_callback smc_table_info;
sqlite_exec_callback smc_foreign_key_list;
db_table_map_t smc_db_list;
};
int walk_sqlite_metadata(sqlite3 *db, struct sqlite_metadata_callbacks &smc);
void attach_sqlite_db(sqlite3 *db, const std::string &filename);
#endif

100
src/sqlite-extension-func.c Normal file
View File

@ -0,0 +1,100 @@
/**
* Copyright (c) 2013, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file sqlite-extension-func.c
*/
#include "config.h"
#include <stdio.h>
#include <assert.h>
#include "sqlite-extension-func.h"
sqlite_registration_func_t sqlite_registration_funcs[] = {
common_extension_functions,
network_extension_functions,
fs_extension_functions,
NULL
};
int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs)
{
int lpc;
assert(db != NULL);
assert(reg_funcs != NULL);
for (lpc = 0; reg_funcs[lpc]; lpc++) {
const struct FuncDef *basic_funcs = NULL;
const struct FuncDefAgg *agg_funcs = NULL;
int i;
reg_funcs[lpc](&basic_funcs, &agg_funcs);
for (i = 0; basic_funcs && basic_funcs[i].zName; i++) {
void *pArg = 0;
switch (basic_funcs[i].argType) {
case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break;
}
//sqlite3CreateFunc
/* LMH no error checking */
sqlite3_create_function(db,
basic_funcs[i].zName,
basic_funcs[i].nArg,
basic_funcs[i].eTextRep,
pArg,
basic_funcs[i].xFunc,
0,
0);
}
for (i = 0; agg_funcs && agg_funcs[i].zName; i++) {
void *pArg = 0;
switch (agg_funcs[i].argType) {
case 1: pArg = db; break;
case 2: pArg = (void *)(-1); break;
}
//sqlite3CreateFunc
sqlite3_create_function(db,
agg_funcs[i].zName,
agg_funcs[i].nArg,
SQLITE_UTF8,
pArg,
0,
agg_funcs[i].xStep,
agg_funcs[i].xFinalize);
}
}
return 0;
}

View File

@ -0,0 +1,80 @@
/**
* Copyright (c) 2013, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
* ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @file sqlite-extension-func.h
*/
#ifndef _sqlite_extension_func_h
#define _sqlite_extension_func_h
#include <stdint.h>
#include <sqlite3.h>
#ifdef __cplusplus
extern "C" {
#endif
struct FuncDef {
const char *zName;
signed char nArg;
uint8_t argType; /* 0: none. 1: db 2: (-1) */
uint8_t eTextRep; /* 1: UTF-16. 0: UTF-8 */
uint8_t needCollSeq;
void (*xFunc)(sqlite3_context*,int,sqlite3_value **);
};
struct FuncDefAgg {
const char *zName;
signed char nArg;
uint8_t argType;
uint8_t needCollSeq;
void (*xStep)(sqlite3_context*,int,sqlite3_value**);
void (*xFinalize)(sqlite3_context*);
};
typedef int (*sqlite_registration_func_t)(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs);
int common_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs);
int network_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs);
int fs_extension_functions(const struct FuncDef **basic_funcs,
const struct FuncDefAgg **agg_funcs);
extern sqlite_registration_func_t sqlite_registration_funcs[];
int register_sqlite_funcs(sqlite3 *db, sqlite_registration_func_t *reg_funcs);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -145,6 +145,7 @@ dist_noinst_SCRIPTS = \
test_line_buffer.sh \
test_listview.sh \
test_logfile.sh \
test_sql_coll_func.sh \
test_sql_fs_func.sh \
test_view_colors.sh \
test_vt52_curses.sh
@ -193,6 +194,7 @@ TESTS = test_bookmarks \
test_hist_source \
test_listview.sh \
test_pcrepp \
test_sql_coll_func.sh \
test_sql_fs_func.sh \
test_view_colors.sh \
test_vt52_curses.sh \

View File

@ -93,8 +93,8 @@ TESTS = test_bookmarks$(EXEEXT) test_auto_fd$(EXEEXT) \
test_auto_mem$(EXEEXT) test_line_buffer.sh \
test_line_buffer2$(EXEEXT) test_grep_proc.sh \
test_grep_proc2$(EXEEXT) test_hist_source$(EXEEXT) \
test_listview.sh test_pcrepp$(EXEEXT) test_sql_fs_func.sh \
test_view_colors.sh test_vt52_curses.sh \
test_listview.sh test_pcrepp$(EXEEXT) test_sql_coll_func.sh \
test_sql_fs_func.sh test_view_colors.sh test_vt52_curses.sh \
test_top_status$(EXEEXT) test_data_parser.sh
subdir = test
DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
@ -713,6 +713,7 @@ dist_noinst_SCRIPTS = \
test_line_buffer.sh \
test_listview.sh \
test_logfile.sh \
test_sql_coll_func.sh \
test_sql_fs_func.sh \
test_view_colors.sh \
test_vt52_curses.sh
@ -1404,6 +1405,13 @@ test_pcrepp.log: test_pcrepp$(EXEEXT)
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test_sql_coll_func.sh.log: test_sql_coll_func.sh
@p='test_sql_coll_func.sh'; \
b='test_sql_coll_func.sh'; \
$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
--log-file $$b.log --trs-file $$b.trs \
$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
"$$tst" $(AM_TESTS_FD_REDIRECT)
test_sql_fs_func.sh.log: test_sql_fs_func.sh
@p='test_sql_fs_func.sh'; \
b='test_sql_fs_func.sh'; \

View File

@ -6,6 +6,7 @@
#include <sqlite3.h>
#include "auto_mem.hh"
#include "sqlite-extension-func.h"
struct callback_state {
int cs_row;
@ -28,13 +29,6 @@ static int sql_callback(void *ptr,
return 0;
}
extern "C" {
int RegisterExtensionFunctions(sqlite3 *db);
}
int register_network_extension_functions(sqlite3 *db);
int register_fs_extension_functions(sqlite3 *db);
int main(int argc, char *argv[])
{
int retval = EXIT_SUCCESS;
@ -57,9 +51,7 @@ int main(int argc, char *argv[])
{
int register_collation_functions(sqlite3 * db);
RegisterExtensionFunctions(db.in());
register_network_extension_functions(db.in());
register_fs_extension_functions(db.in());
register_sqlite_funcs(db.in(), sqlite_registration_funcs);
register_collation_functions(db.in());
}

View File

@ -0,0 +1,65 @@
#! /bin/bash
run_test ./drive_sql "select '192.168.1.10' < '192.168.1.2'"
check_output "" <<EOF
Row 0:
Column '192.168.1.10' < '192.168.1.2': 1
EOF
run_test ./drive_sql "select '192.168.1.10' < '192.168.1.2' collate ipaddress"
check_output "" <<EOF
Row 0:
Column '192.168.1.10' < '192.168.1.2' collate ipaddress: 0
EOF
run_test ./drive_sql "select '::ffff:192.168.1.10' = '192.168.1.10' collate ipaddress"
check_output "" <<EOF
Row 0:
Column '::ffff:192.168.1.10' = '192.168.1.10' collate ipaddress: 1
EOF
run_test ./drive_sql "select 'fe80::a85f:80b4:5cbe:8691' = 'fe80:0000:0000:0000:a85f:80b4:5cbe:8691' collate ipaddress"
check_output "" <<EOF
Row 0:
Column 'fe80::a85f:80b4:5cbe:8691' = 'fe80:0000:0000:0000:a85f:80b4:5cbe:8691' collate ipaddress: 1
EOF
run_test ./drive_sql "select '' < '192.168.1.2' collate ipaddress"
check_output "" <<EOF
Row 0:
Column '' < '192.168.1.2' collate ipaddress: 1
EOF
run_test ./drive_sql "select '192.168.1.2' > '' collate ipaddress"
check_output "" <<EOF
Row 0:
Column '192.168.1.2' > '' collate ipaddress: 1
EOF
run_test ./drive_sql "select '192.168.1.2' < 'fe80::a85f:80b4:5cbe:8691' collate ipaddress"
check_output "" <<EOF
Row 0:
Column '192.168.1.2' < 'fe80::a85f:80b4:5cbe:8691' collate ipaddress: 1
EOF
run_test ./drive_sql "select 'file10.txt' < 'file2.txt'"
check_output "" <<EOF
Row 0:
Column 'file10.txt' < 'file2.txt': 1
EOF
run_test ./drive_sql "select 'file10.txt' < 'file2.txt' collate naturalcase"
check_output "" <<EOF
Row 0:
Column 'file10.txt' < 'file2.txt' collate naturalcase: 0
EOF