diff options
| author | Felix Perktold <Felix.Perktold@student.uibk.ac.at> | 2026-01-18 17:44:10 +0100 |
|---|---|---|
| committer | Felix Perktold <Felix.Perktold@student.uibk.ac.at> | 2026-01-18 17:44:10 +0100 |
| commit | 07cd615c7e1cafccd6d46b3eb68d413f2a2dd9a5 (patch) | |
| tree | 540292fc4029265628ea7e4d2d750c21c267a85b | |
| parent | a2ab90cfb9e364a3de7157b2ea2905e4c944583d (diff) | |
start writing psql module, start writing exercise 1 with that module, small header file changes as needed for module programming
| -rw-r--r-- | Makefile | 7 | ||||
| -rw-r--r-- | lisp.c | 6 | ||||
| -rw-r--r-- | lisp.h | 3 | ||||
| -rw-r--r-- | lisp/exercise_1.lisp | 21 | ||||
| -rw-r--r-- | lisp_api.h | 5 | ||||
| -rw-r--r-- | modules/psql_lisp.c | 85 |
6 files changed, 118 insertions, 9 deletions
@@ -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 @@ -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) { @@ -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")) @@ -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; +} |
