summary refs log tree commit diff
path: root/scoop.c
diff options
context:
space:
mode:
authorJune McEnroe <june@causal.agency>2020-05-21 13:55:25 -0400
committerJune McEnroe <june@causal.agency>2020-05-21 13:55:25 -0400
commita6e1441bec7609a121e442bb75100a61a43f0258 (patch)
tree335023069987fb23d94efcb121c86730458a81ca /scoop.c
parentExpand and clarify documentation (diff)
downloadlitterbox-a6e1441bec7609a121e442bb75100a61a43f0258.tar.gz
litterbox-a6e1441bec7609a121e442bb75100a61a43f0258.zip
Do not sort results in scoop by default
The -s flag now enables sorting (-g and -l also imply it), while the -S
flag now launches the sqlite3 shell.

Avoiding sorting by default is much faster and less memory-intensive as
it doesn't require loading the entire result set into memory at once.
Diffstat (limited to 'scoop.c')
-rw-r--r--scoop.c63
1 files changed, 29 insertions, 34 deletions
diff --git a/scoop.c b/scoop.c
index 4c4ee35..3ab6e5d 100644
--- a/scoop.c
+++ b/scoop.c
@@ -295,7 +295,7 @@ static void regexp(sqlite3_context *ctx, int n, sqlite3_value *args[]) {
 	sqlite3_result_int(ctx, !error);
 }
 
-static const char *Inner = SQL(
+static const char *Query = SQL(
 	SELECT
 		contexts.network,
 		contexts.name AS context,
@@ -343,16 +343,6 @@ static const char *Limit = SQL(
 	LIMIT coalesce(:limit, -1)
 );
 
-static const char *Outer = SQL(
-	SELECT * FROM results
-	ORDER BY time, event
-);
-
-static const char *Group = SQL(
-	SELECT * FROM results
-	ORDER BY network, context, time, event
-);
-
 static const char *TypeNames[] = {
 #define X(id, name) [id] = name,
 	ENUM_TYPE
@@ -395,35 +385,38 @@ int main(int argc, char *argv[]) {
 
 	char *path = NULL;
 	bool shell = false;
-	bool group = false;
 	Format *format = (tty ? formatColor : formatPlain);
 
-	int n = 0;
-	struct Bind binds[argc];
+	bool sort = false;
+	bool group = false;
 	const char *search = NULL;
 	const char *where = NULL;
+	const char *limit = NULL;
 
-	const char *Opts = "D:F:LN:T:a:b:c:d:f:gh:l:m:n:pqst:u:vw:";
+	int n = 0;
+	struct Bind binds[argc];
+	const char *Opts = "D:F:LN:ST:a:b:c:d:f:gh:l:m:n:pqst:u:vw:";
 	for (int opt; 0 < (opt = getopt(argc, argv, Opts));) {
 		switch (opt) {
 			break; case 'D': binds[n++] = Bind(":date", optarg, 0);
 			break; case 'F': binds[n++] = Bind(":format", optarg, 0);
 			break; case 'L': binds[n++] = Bind(":local", NULL, 1);
 			break; case 'N': binds[n++] = Bind(":network", optarg, 0);
+			break; case 'S': shell = true;
 			break; case 'T': binds[n++] = Bind(":target", optarg, 0);
 			break; case 'a': binds[n++] = Bind(":after", optarg, 0);
 			break; case 'b': binds[n++] = Bind(":before", optarg, 0);
 			break; case 'c': binds[n++] = Bind(":context", optarg, 0);
 			break; case 'd': path = optarg;
 			break; case 'f': format = parseFormat(optarg);
-			break; case 'g': group = true;
+			break; case 'g': group = true; sort = true;
 			break; case 'h': binds[n++] = Bind(":host", optarg, 0);
-			break; case 'l': binds[n++] = Bind(":limit", optarg, 0);
+			break; case 'l': limit = optarg; sort = true;
 			break; case 'm': binds[n++] = Bind(":regexp", optarg, 0);
 			break; case 'n': binds[n++] = Bind(":nick", optarg, 0);
 			break; case 'p': binds[n++] = Bind(":query", NULL, 0);
 			break; case 'q': binds[n++] = Bind(":query", NULL, 1);
-			break; case 's': shell = true;
+			break; case 's': sort = true;
 			break; case 't': binds[n++] = Bind(":type", NULL, parseType(optarg));
 			break; case 'u': binds[n++] = Bind(":user", optarg, 0);
 			break; case 'v': verbose = true;
@@ -450,25 +443,27 @@ int main(int argc, char *argv[]) {
 		err(EX_UNAVAILABLE, "sqlite3");
 	}
 
-	int len;
 	char sql[4096];
-	if (search) {
-		len = snprintf(
-			sql, sizeof(sql),
-			"WITH results AS (%s AND %s AND %s %s) %s;",
-			Inner, Search, (where ? where : "true"), Limit,
-			(group ? Group : Outer)
-		);
-		binds[n++] = Bind(":search", search, 0);
-	} else {
-		len = snprintf(
-			sql, sizeof(sql),
-			"WITH results AS (%s AND %s %s) %s;",
-			Inner, (where ? where : "true"), Limit, (group ? Group : Outer)
-		);
-	}
+	int len = snprintf(
+		sql, sizeof(sql),
+		SQL(
+			WITH results AS (
+				%s AND %s AND %s
+				%s
+			)
+			SELECT * FROM results %s %s %s;
+		),
+		Query, (search ? Search : "true"), (where ? where : "true"),
+		(limit ? Limit : ""),
+		(sort ? "ORDER BY" : ""),
+		(group ? "network, context," : ""),
+		(sort ? "time, event" : "")
+	);
 	assert((size_t)len < sizeof(sql));
 
+	if (search) binds[n++] = Bind(":search", search, 0);
+	if (limit) binds[n++] = Bind(":limit", limit, 0);
+
 	sqlite3_stmt *stmt = dbPrepare(sql);
 	for (int i = 0; i < n; ++i) {
 		if (binds[i].text) {