summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Perktold <Felix.Perktold@student.uibk.ac.at>2026-01-18 17:44:10 +0100
committerFelix Perktold <Felix.Perktold@student.uibk.ac.at>2026-01-18 17:44:10 +0100
commit07cd615c7e1cafccd6d46b3eb68d413f2a2dd9a5 (patch)
tree540292fc4029265628ea7e4d2d750c21c267a85b
parenta2ab90cfb9e364a3de7157b2ea2905e4c944583d (diff)
start writing psql module, start writing exercise 1 with that module, small header file changes as needed for module programming
-rw-r--r--Makefile7
-rw-r--r--lisp.c6
-rw-r--r--lisp.h3
-rw-r--r--lisp/exercise_1.lisp21
-rw-r--r--lisp_api.h5
-rw-r--r--modules/psql_lisp.c85
6 files changed, 118 insertions, 9 deletions
diff --git a/Makefile b/Makefile
index d574b4e..ad69623 100644
--- a/Makefile
+++ b/Makefile
@@ -5,8 +5,9 @@ CFLAGS = -DYYDEBUG=1 -fPIC
LIBS = -lreadline -lfl -lm
OBJS = lisp.o lisp.tab.o lex.yy.o
-MODULE_SRC = $(wildcard modules/*.c)
-MODULE_SO = $(MODULE_SRC:.c=.so)
+MODULE_LIBS = -lpq
+MODULE_SRC = $(wildcard modules/*.c)
+MODULE_SO = $(MODULE_SRC:.c=.so)
.SUFFIXES:
main: main.c $(OBJS)
@@ -48,7 +49,7 @@ modules: $(MODULE_SO)
modules/%.so: modules/%.c lisp.o
gcc -fPIC -c $< -o $*.o
- gcc -fPIC -shared $*.o lisp.o -o $@
+ gcc -fPIC -shared $*.o lisp.o -o $@ $(MODULE_LIBS)
rm $*.o
.PHONY: clean test run
diff --git a/lisp.c b/lisp.c
index 8b9f3ad..88ff472 100644
--- a/lisp.c
+++ b/lisp.c
@@ -26,14 +26,14 @@ value *make_double(double d) {
value *make_symbol(const char *s) {
value *val = malloc(sizeof(value));
val->type = VT_SYMBOL;
- val->as.sym = s;
+ val->as.sym = strdup(s);
return val;
}
value *make_string(const char *s) {
value *val = malloc(sizeof(value));
val->type = VT_STRING;
- val->as.str = s;
+ val->as.str = strdup(s);
return val;
}
@@ -518,7 +518,7 @@ value *procedure_load_module(env *e, value *args) {
env_define(e, exports[i].name, exports[i].v);
}
- return make_nil();
+ return make_int(1);
}
int is_integer(double x) {
diff --git a/lisp.h b/lisp.h
index 7d435ff..ef4505a 100644
--- a/lisp.h
+++ b/lisp.h
@@ -4,8 +4,6 @@
typedef struct value value;
typedef struct env env;
-void print_value(value *val);
-void println_value(value *val);
// environments, TODO: make this use hashtable
// symbol->val
typedef struct env {
@@ -21,7 +19,6 @@ value *env_lookup(env *e, const char *sym);
extern env *global_env;
-value *eval(env *e, value *val);
value *eval_pair(env *e, value *val);
value *apply(value *lambda, value *args);
diff --git a/lisp/exercise_1.lisp b/lisp/exercise_1.lisp
new file mode 100644
index 0000000..2828ae4
--- /dev/null
+++ b/lisp/exercise_1.lisp
@@ -0,0 +1,21 @@
+(load_module "modules/psql_lisp.so")
+(define result (pg_execute "dbname=pagilla user=postgres" "SELECT category.name AS category_name,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 1) AS mon,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 2) AS tue,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 3) AS wed,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 4) AS thu,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 5) AS fri,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 6) AS sat,
+ COUNT(*) FILTER (WHERE EXTRACT(ISODOW FROM rental.rental_date) = 7) AS sun,
+ COUNT(*) AS total
+FROM rental
+INNER JOIN inventory
+ON rental.inventory_id = inventory.inventory_id
+INNER JOIN film_category
+ON inventory.film_id = film_category.film_id
+INNER JOIN category
+ON film_category.category_id = category.category_id
+WHERE EXTRACT(MONTH FROM rental.rental_date) = 6 AND
+ EXTRACT(YEAR FROM rental.rental_date) = 2005
+GROUP BY category.name
+ORDER BY category.name"))
diff --git a/lisp_api.h b/lisp_api.h
index bb4bf6f..66ad231 100644
--- a/lisp_api.h
+++ b/lisp_api.h
@@ -4,6 +4,11 @@
typedef struct value value;
typedef struct env env;
+value *eval(env *e, value *val);
+
+void print_value(value *val);
+void println_value(value *val);
+
typedef enum {
VT_INT,
VT_DOUBLE,
diff --git a/modules/psql_lisp.c b/modules/psql_lisp.c
new file mode 100644
index 0000000..87ea748
--- /dev/null
+++ b/modules/psql_lisp.c
@@ -0,0 +1,85 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <libpq-fe.h>
+#include "../lisp_api.h"
+
+value *hello_fun(env *e, value *args) {
+ printf("Hello from dynamically loaded module!\n");
+ return make_nil();
+}
+
+value *pg_execute(env *e, value *args) {
+ value *fst_arg = eval(e, car(args));
+ value *snd_arg = eval(e, car(cdr(args)));
+
+ if (fst_arg->type != VT_STRING) {
+ printf("not a string:");
+ println_value(fst_arg);
+ return make_nil(); //TODO: make error
+ }
+ if (snd_arg->type != VT_STRING) {
+ printf("not a string:");
+ println_value(snd_arg);
+ return make_nil(); //TODO: make error
+ }
+
+ const char *conn_str = fst_arg->as.str;
+ const char *query_str = snd_arg->as.str;
+
+ PGconn *conn = PQconnectdb(conn_str);
+ if (PQstatus(conn) != CONNECTION_OK) {
+ fprintf(stderr, "Connection failed: %s", PQerrorMessage(conn));
+ PQfinish(conn);
+ return make_nil(); //TODO: make error
+ }
+
+ PGresult *res = PQexec(conn, query_str);
+ if (PQresultStatus(res) != PGRES_TUPLES_OK) {
+ fprintf(stderr, "Query failed: %s", PQerrorMessage(conn));
+ PQclear(res);
+ PQfinish(conn);
+ return make_nil(); //TODO: make error
+ }
+
+ int rows = PQntuples(res);
+ int cols = PQnfields(res);
+
+ value *table = make_nil();
+
+ for (int row = 0; row < rows; row++) {
+ value *row_val = make_nil();
+ for (int col = 0; col < cols; col++) {
+ switch (PQftype(res, col)) {
+ case 23:
+ row_val=cons(make_int(atoi(PQgetvalue(res, row, col))), row_val);
+ break;
+ case 1700:
+ case 20:
+ row_val=cons(make_int(atof(PQgetvalue(res, row, col))), row_val);
+ break;
+ default:
+ const char *str;
+ row_val=cons(make_string(PQgetvalue(res, row, col)), row_val);
+ break;
+ }
+ }
+ table = cons(reverse(row_val), table);
+ }
+ PQclear(res);
+ PQfinish(conn);
+
+ table = reverse(table);
+ return table;
+}
+
+module_export *module_init() {
+ static module_export exports[2];
+
+ exports[0].name = "pg_execute";
+ exports[0].v = make_procedure(&pg_execute);
+
+ exports[1].name = NULL;
+ exports[1].v = NULL;
+
+ return exports;
+}