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:
parent
178937886c
commit
5ba3097ee7
@ -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 \
|
||||
|
@ -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@
|
||||
|
@ -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
|
||||
|
@ -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];
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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(),
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
370
src/lnav.cc
370
src/lnav.cc
@ -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());
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
80
src/lnav_config.cc
Normal 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
62
src/lnav_config.hh
Normal 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
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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];
|
||||
|
||||
|
@ -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:
|
||||
|
@ -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
405
src/sql_util.cc
Normal 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
61
src/sql_util.hh
Normal 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
100
src/sqlite-extension-func.c
Normal 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;
|
||||
}
|
80
src/sqlite-extension-func.h
Normal file
80
src/sqlite-extension-func.h
Normal 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
|
@ -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 \
|
||||
|
@ -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'; \
|
||||
|
@ -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());
|
||||
}
|
||||
|
||||
|
65
test/test_sql_coll_func.sh
Normal file
65
test/test_sql_coll_func.sh
Normal 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
|
Loading…
Reference in New Issue
Block a user