1 /*
    2  * WARNING: automatically generated by ort 0.14.0.
    3  * DO NOT EDIT!
    4  */
    5 #include <sys/queue.h>
    6 
    7 #include <assert.h>
    8 /*
    9  * Required for b64_ntop().
   10  */
   11 #include <ctype.h>
   12 #include <netinet/in.h>
   13 #include <resolv.h>
   14 #include <stdio.h>
   15 #include <stdint.h> /* int64_t */
   16 #include <stdlib.h>
   17 #include <string.h>
   18 #include <time.h> /* _XOPEN_SOURCE and gmtime_r()*/
   19 #include <unistd.h>
   20 
   21 #include <sqlbox.h>
   22 
   23 #include "db.h"
   24 
   25 /*
   26  * All SQL statements we'll later define in "stmts".
   27  */
   28 enum	stmt {
   29 	STMT_company_BY_UNIQUE_id,
   30 	STMT_company_BY_SEARCH_0,
   31 	STMT_company_INSERT,
   32 	STMT_company_DELETE_0,
   33 	STMT_user_BY_UNIQUE_email,
   34 	STMT_user_BY_UNIQUE_uid,
   35 	STMT_user_BY_SEARCH_0,
   36 	STMT_user_BY_SEARCH_1,
   37 	STMT_user_BY_SEARCH_2,
   38 	STMT_user_INSERT,
   39 	STMT_user_UPDATE_0,
   40 	STMT_user_UPDATE_1,
   41 	STMT_user_DELETE_0,
   42 	STMT_session_BY_UNIQUE_id,
   43 	STMT_session_BY_SEARCH_0,
   44 	STMT_session_INSERT,
   45 	STMT_session_DELETE_0,
   46 	STMT__MAX
   47 };
   48 
   49 /*
   50  * Definition of our opaque "ort", which contains role information.
   51  */
   52 struct	ort {
   53 	/* Hidden database connection */
   54 	struct sqlbox *db;
   55 };
   56 
   57 /*
   58  * Table columns.
   59  * The macro accepts a table name because we use AS statements a lot.
   60  * This is because tables can appear multiple times in a single query and 
   61  * need aliasing.
   62  */
   63 #define DB_SCHEMA_company(_x) \
   64 	#_x ".name" "," \
   65 	#_x ".id" "," \
   66 	#_x ".somenum"
   67 #define DB_SCHEMA_user(_x) \
   68 	#_x ".cid" "," \
   69 	#_x ".sex" "," \
   70 	#_x ".hash" "," \
   71 	#_x ".email" "," \
   72 	#_x ".image" "," \
   73 	#_x ".name" "," \
   74 	#_x ".uid"
   75 #define DB_SCHEMA_session(_x) \
   76 	#_x ".userid" "," \
   77 	#_x ".token" "," \
   78 	#_x ".mtime" "," \
   79 	#_x ".id"
   80 
   81 /*
   82  * Our full set of SQL statements.
   83  * We define these beforehand because that's how sqlbox(3) handles 
   84  * statement generation.
   85  * Notice the "AS" part: this allows for multiple inner joins without 
   86  * ambiguity.
   87  */
   88 static	const char *const stmts[STMT__MAX] = {
   89 	/* STMT_company_BY_UNIQUE_id */
   90 	"SELECT " DB_SCHEMA_company(company) " FROM company WHERE company.id = ?",
   91 	/* STMT_company_BY_SEARCH_0 */
   92 	"SELECT " DB_SCHEMA_company(company) " FROM company "
   93 		"WHERE company.somenum ISNULL",
   94 	/* STMT_company_INSERT */
   95 	"INSERT INTO company (name,somenum) VALUES (?,?)",
   96 	/* STMT_company_DELETE_0 */
   97 	"DELETE FROM company",
   98 	/* STMT_user_BY_UNIQUE_email */
   99 	"SELECT " DB_SCHEMA_user(user) "," DB_SCHEMA_company(_a) " FROM user "
  100 		"INNER JOIN company AS _a ON _a.id=user.cid "
  101 		"WHERE user.email = ?",
  102 	/* STMT_user_BY_UNIQUE_uid */
  103 	"SELECT " DB_SCHEMA_user(user) "," DB_SCHEMA_company(_a) " FROM user "
  104 		"INNER JOIN company AS _a ON _a.id=user.cid "
  105 		"WHERE user.uid = ?",
  106 	/* STMT_user_BY_SEARCH_0 */
  107 	"SELECT " DB_SCHEMA_user(user) "," DB_SCHEMA_company(_a) " FROM user "
  108 		"INNER JOIN company AS _a ON _a.id=user.cid "
  109 		"WHERE user.name = ? LIMIT 5",
  110 	/* STMT_user_BY_SEARCH_1 */
  111 	"SELECT " DB_SCHEMA_user(user) "," DB_SCHEMA_company(_a) " FROM user "
  112 		"INNER JOIN company AS _a ON _a.id=user.cid "
  113 		"WHERE user.email = ?",
  114 	/* STMT_user_BY_SEARCH_2 */
  115 	"SELECT " DB_SCHEMA_user(user) "," DB_SCHEMA_company(_a) " FROM user "
  116 		"INNER JOIN company AS _a ON _a.id=user.cid "
  117 		"WHERE user.uid = ? ORDER BY _a.name ASC",
  118 	/* STMT_user_INSERT */
  119 	"INSERT INTO user (cid,sex,hash,email,image,name) VALUES (?,?,?,?,"
  120 		" ?,?)",
  121 	/* STMT_user_UPDATE_0 */
  122 	"UPDATE user SET hash = ? WHERE uid = ?",
  123 	/* STMT_user_UPDATE_1 */
  124 	"UPDATE user SET email = ? WHERE uid = ?",
  125 	/* STMT_user_DELETE_0 */
  126 	"DELETE FROM user",
  127 	/* STMT_session_BY_UNIQUE_id */
  128 	"SELECT " DB_SCHEMA_session(session) "," DB_SCHEMA_user(_b) "," 
  129 		DB_SCHEMA_company(_c) " FROM session "
  130 		"INNER JOIN user AS _b ON _b.uid=session.userid "
  131 		"INNER JOIN company AS _c ON _c.id=_b.cid "
  132 		"WHERE session.id = ?",
  133 	/* STMT_session_BY_SEARCH_0 */
  134 	"SELECT " DB_SCHEMA_session(session) "," DB_SCHEMA_user(_b) "," 
  135 		DB_SCHEMA_company(_c) " FROM session "
  136 		"INNER JOIN user AS _b ON _b.uid=session.userid "
  137 		"INNER JOIN company AS _c ON _c.id=_b.cid "
  138 		"WHERE _c.name = ? AND session.mtime = ?",
  139 	/* STMT_session_INSERT */
  140 	"INSERT INTO session (userid,token,mtime) VALUES (?,?,?)",
  141 	/* STMT_session_DELETE_0 */
  142 	"DELETE FROM session WHERE id = ?",
  143 };
  144 
  145 /*
  146  * Finally, all of the functions we'll use.
  147  * All of the non-static functions are documented in the associated 
  148  * header file.
  149  */
  150 
  151 void
  152 db_trans_open(struct ort *ctx, size_t id, int mode)
  153 {
  154 	struct sqlbox *db = ctx->db;
  155 	int c;
  156 
  157 	if (mode < 0)
  158 		c = sqlbox_trans_exclusive(db, 0, id);
  159 	else if (mode > 0)
  160 		c = sqlbox_trans_immediate(db, 0, id);
  161 	else
  162 		c = sqlbox_trans_deferred(db, 0, id);
  163 	if (!c)
  164 		exit(EXIT_FAILURE);
  165 }
  166 
  167 void
  168 db_trans_rollback(struct ort *ctx, size_t id)
  169 {
  170 	struct sqlbox *db = ctx->db;
  171 
  172 	if (!sqlbox_trans_rollback(db, 0, id))
  173 		exit(EXIT_FAILURE);
  174 }
  175 
  176 void
  177 db_trans_commit(struct ort *ctx, size_t id)
  178 {
  179 	struct sqlbox *db = ctx->db;
  180 
  181 	if (!sqlbox_trans_commit(db, 0, id))
  182 		exit(EXIT_FAILURE);
  183 }
  184 
  185 void
  186 db_logging_data(struct ort *ort, const void *arg, size_t sz)
  187 {
  188 
  189 	if (!sqlbox_msg_set_dat(ort->db, arg, sz))
  190 		exit(EXIT_FAILURE);
  191 }
  192 
  193 struct ort *
  194 db_open(const char *file)
  195 {
  196 
  197 	return db_open_logging(file, NULL, NULL, NULL);
  198 }
  199 
  200 struct ort *
  201 db_open_logging(const char *file,
  202 	void (*log)(const char *, void *),
  203 	void (*log_short)(const char *, ...), void *log_arg)
  204 {
  205 	size_t i;
  206 	struct ort *ctx = NULL;
  207 	struct sqlbox_cfg cfg;
  208 	struct sqlbox *db = NULL;
  209 	struct sqlbox_pstmt pstmts[STMT__MAX];
  210 	struct sqlbox_src srcs[1] = {
  211 		{ .fname = (char *)file,
  212 		  .mode = SQLBOX_SRC_RW }
  213 	};
  214 
  215 	memset(&cfg, 0, sizeof(struct sqlbox_cfg));
  216 	cfg.msg.func = log;
  217 	cfg.msg.func_short = log_short;
  218 	cfg.msg.dat = log_arg;
  219 	cfg.srcs.srcs = srcs;
  220 	cfg.srcs.srcsz = 1;
  221 	cfg.stmts.stmts = pstmts;
  222 	cfg.stmts.stmtsz = STMT__MAX;
  223 
  224 	for (i = 0; i < STMT__MAX; i++)
  225 		pstmts[i].stmt = (char *)stmts[i];
  226 
  227 	ctx = malloc(sizeof(struct ort));
  228 	if (ctx == NULL)
  229 		goto err;
  230 
  231 	if ((db = sqlbox_alloc(&cfg)) == NULL)
  232 		goto err;
  233 	ctx->db = db;
  234 
  235 	/*
  236 	 * Now actually open the database.
  237 	 * If this succeeds, then we're good to go.
  238 	 */
  239 
  240 	if (sqlbox_open_async(db, 0))
  241 		return ctx;
  242 err:
  243 	sqlbox_free(db);
  244 	free(ctx);
  245 	return NULL;
  246 }
  247 
  248 void
  249 db_close(struct ort *p)
  250 {
  251 	if (p == NULL)
  252 		return;
  253 	sqlbox_free(p->db);
  254 	free(p);
  255 }
  256 
  257 /*
  258  * Fill in a company from an open statement "stmt".
  259  * This starts grabbing results from "pos", which may be NULL to start 
  260  * from zero.
  261  * This follows DB_SCHEMA_company's order for columns.
  262  */
  263 static void
  264 db_company_fill(struct ort *ctx, struct company *p, const struct sqlbox_parmset *set, size_t *pos)
  265 {
  266 	size_t i = 0;
  267 	int64_t tmpint;
  268 
  269 	if (pos == NULL)
  270 		pos = &i;
  271 	memset(p, 0, sizeof(*p));
  272 	if (sqlbox_parm_string_alloc
  273 	    (&set->ps[(*pos)++], &p->name, NULL) == -1)
  274 		exit(EXIT_FAILURE);
  275 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  276 		exit(EXIT_FAILURE);
  277 	ORT_SET_company_id(p, tmpint);
  278 	p->has_somenum = set->ps[*pos].type != SQLBOX_PARM_NULL;
  279 	if (p->has_somenum) {
  280 		if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  281 			exit(EXIT_FAILURE);
  282 		ORT_SET_company_somenum(p, tmpint);
  283 	} else
  284 		(*pos)++;
  285 }
  286 
  287 static void
  288 db_company_fill_r(struct ort *ctx, struct company *p,
  289 	const struct sqlbox_parmset *res, size_t *pos)
  290 {
  291 	size_t i = 0;
  292 
  293 	if (pos == NULL)
  294 		pos = &i;
  295 	db_company_fill(ctx, p, res, pos);
  296 }
  297 
  298 /*
  299  * Free resources from "p" and all nested objects.
  300  * Does not free the "p" pointer itself.
  301  * Has no effect if "p" is NULL.
  302  */
  303 static void
  304 db_company_unfill(struct company *p)
  305 {
  306 	if (p == NULL)
  307 		return;
  308 	free(p->name);
  309 }
  310 
  311 static void
  312 db_company_unfill_r(struct company *p)
  313 {
  314 	if (p == NULL)
  315 		return;
  316 	db_company_unfill(p);
  317 }
  318 
  319 void
  320 db_company_free(struct company *p)
  321 {
  322 	db_company_unfill_r(p);
  323 	free(p);
  324 }
  325 
  326 void
  327 db_company_freeq(struct company_q *q)
  328 {
  329 	struct company *p;
  330 
  331 	if (q == NULL)
  332 		return;
  333 	while ((p = TAILQ_FIRST(q)) != NULL) {
  334 		TAILQ_REMOVE(q, p, _entries);
  335 		db_company_free(p);
  336 	}
  337 	free(q);
  338 }
  339 
  340 int64_t
  341 db_company_insert(struct ort *ctx, const char *v1, company_somenum *v2)
  342 {
  343 	enum sqlbox_code rc;
  344 	int64_t id = -1;
  345 	struct sqlbox *db = ctx->db;
  346 	struct sqlbox_parm parms[2];
  347 
  348 	memset(parms, 0, sizeof(parms));
  349 	parms[0].sparm = v1;
  350 	parms[0].type = SQLBOX_PARM_STRING;
  351 	if (v2 == NULL) {
  352 		parms[1].type = SQLBOX_PARM_NULL;
  353 	} else {
  354 		parms[1].iparm = ORT_GETV_company_somenum(*v2);
  355 		parms[1].type = SQLBOX_PARM_INT;
  356 	}
  357 
  358 	rc = sqlbox_exec(db, 0, STMT_company_INSERT, 
  359 	     2, parms, SQLBOX_STMT_CONSTRAINT);
  360 	if (rc == SQLBOX_CODE_ERROR)
  361 		exit(EXIT_FAILURE);
  362 	else if (rc != SQLBOX_CODE_OK)
  363 		return (-1);
  364 	if (!sqlbox_lastid(db, 0, &id))
  365 		exit(EXIT_FAILURE);
  366 	return id;
  367 }
  368 
  369 struct company_q *
  370 db_company_list_by_somenum_isnull(struct ort *ctx)
  371 {
  372 	struct company *p;
  373 	struct company_q *q;
  374 	const struct sqlbox_parmset *res;
  375 	struct sqlbox *db = ctx->db;
  376 
  377 	q = malloc(sizeof(struct company_q));
  378 	if (q == NULL) {
  379 		perror(NULL);
  380 		exit(EXIT_FAILURE);
  381 	}
  382 	TAILQ_INIT(q);
  383 
  384 	if (!sqlbox_prepare_bind_async
  385 	    (db, 0, STMT_company_BY_SEARCH_0,
  386 	     0, NULL, SQLBOX_STMT_MULTI))
  387 		exit(EXIT_FAILURE);
  388 	while ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  389 		p = malloc(sizeof(struct company));
  390 		if (p == NULL) {
  391 			perror(NULL);
  392 			exit(EXIT_FAILURE);
  393 		}
  394 		db_company_fill_r(ctx, p, res, NULL);
  395 		TAILQ_INSERT_TAIL(q, p, _entries);
  396 	}
  397 	if (res == NULL)
  398 		exit(EXIT_FAILURE);
  399 	if (!sqlbox_finalise(db, 0))
  400 		exit(EXIT_FAILURE);
  401 	return q;
  402 }
  403 
  404 void
  405 db_company_delete(struct ort *ctx)
  406 {
  407 	enum sqlbox_code c;
  408 	struct sqlbox *db = ctx->db;
  409 
  410 
  411 	c = sqlbox_exec
  412 		(db, 0, STMT_company_DELETE_0, 0, NULL, 0);
  413 	if (c != SQLBOX_CODE_OK)
  414 		exit(EXIT_FAILURE);
  415 }
  416 
  417 /*
  418  * Fill in a user from an open statement "stmt".
  419  * This starts grabbing results from "pos", which may be NULL to start 
  420  * from zero.
  421  * This follows DB_SCHEMA_user's order for columns.
  422  */
  423 static void
  424 db_user_fill(struct ort *ctx, struct user *p, const struct sqlbox_parmset *set, size_t *pos)
  425 {
  426 	size_t i = 0;
  427 	int64_t tmpint;
  428 
  429 	if (pos == NULL)
  430 		pos = &i;
  431 	memset(p, 0, sizeof(*p));
  432 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  433 		exit(EXIT_FAILURE);
  434 	ORT_SET_user_cid(p, tmpint);
  435 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  436 		exit(EXIT_FAILURE);
  437 	p->sex = (enum sex)tmpint;
  438 	if (sqlbox_parm_string_alloc
  439 	    (&set->ps[(*pos)++], &p->hash, NULL) == -1)
  440 		exit(EXIT_FAILURE);
  441 	if (sqlbox_parm_string_alloc
  442 	    (&set->ps[(*pos)++], &p->email, NULL) == -1)
  443 		exit(EXIT_FAILURE);
  444 	p->has_image = set->ps[*pos].type != SQLBOX_PARM_NULL;
  445 	if (p->has_image) {
  446 		if (sqlbox_parm_blob_alloc(&set->ps[(*pos)++],
  447 		    &p->image, &p->image_sz) == -1)
  448 			exit(EXIT_FAILURE);
  449 	} else
  450 		(*pos)++;
  451 	if (sqlbox_parm_string_alloc
  452 	    (&set->ps[(*pos)++], &p->name, NULL) == -1)
  453 		exit(EXIT_FAILURE);
  454 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  455 		exit(EXIT_FAILURE);
  456 	ORT_SET_user_uid(p, tmpint);
  457 }
  458 
  459 static void
  460 db_user_fill_r(struct ort *ctx, struct user *p,
  461 	const struct sqlbox_parmset *res, size_t *pos)
  462 {
  463 	size_t i = 0;
  464 
  465 	if (pos == NULL)
  466 		pos = &i;
  467 	db_user_fill(ctx, p, res, pos);
  468 	db_company_fill_r(ctx, &p->company, res, pos);
  469 }
  470 
  471 /*
  472  * Free resources from "p" and all nested objects.
  473  * Does not free the "p" pointer itself.
  474  * Has no effect if "p" is NULL.
  475  */
  476 static void
  477 db_user_unfill(struct user *p)
  478 {
  479 	if (p == NULL)
  480 		return;
  481 	free(p->hash);
  482 	free(p->email);
  483 	free(p->image);
  484 	free(p->name);
  485 }
  486 
  487 static void
  488 db_user_unfill_r(struct user *p)
  489 {
  490 	if (p == NULL)
  491 		return;
  492 	db_user_unfill(p);
  493 	db_company_unfill_r(&p->company);
  494 }
  495 
  496 void
  497 db_user_free(struct user *p)
  498 {
  499 	db_user_unfill_r(p);
  500 	free(p);
  501 }
  502 
  503 int64_t
  504 db_user_insert(struct ort *ctx, company_id v1, enum sex v2, const char *v3,
  505      const char *v4,
  506      size_t v5_sz, const void **v5,
  507      const char *v6)
  508 {
  509 	enum sqlbox_code rc;
  510 	int64_t id = -1;
  511 	struct sqlbox *db = ctx->db;
  512 	struct sqlbox_parm parms[6];
  513 	char hash1[64];
  514 
  515 	crypt_newhash(v3, "blowfish,a", hash1, sizeof(hash1));
  516 
  517 	memset(parms, 0, sizeof(parms));
  518 	parms[0].iparm = ORT_GETV_user_cid(v1);
  519 	parms[0].type = SQLBOX_PARM_INT;
  520 	parms[1].iparm = v2;
  521 	parms[1].type = SQLBOX_PARM_INT;
  522 	parms[2].sparm = hash1;
  523 	parms[2].type = SQLBOX_PARM_STRING;
  524 	parms[3].sparm = v4;
  525 	parms[3].type = SQLBOX_PARM_STRING;
  526 	if (v5 == NULL) {
  527 		parms[4].type = SQLBOX_PARM_NULL;
  528 	} else {
  529 		parms[4].bparm = *v5;
  530 		parms[4].type = SQLBOX_PARM_BLOB;
  531 		parms[4].sz = v5_sz;
  532 	}
  533 	parms[5].sparm = v6;
  534 	parms[5].type = SQLBOX_PARM_STRING;
  535 
  536 	rc = sqlbox_exec(db, 0, STMT_user_INSERT, 
  537 	     6, parms, SQLBOX_STMT_CONSTRAINT);
  538 	if (rc == SQLBOX_CODE_ERROR)
  539 		exit(EXIT_FAILURE);
  540 	else if (rc != SQLBOX_CODE_OK)
  541 		return (-1);
  542 	if (!sqlbox_lastid(db, 0, &id))
  543 		exit(EXIT_FAILURE);
  544 	return id;
  545 }
  546 
  547 void
  548 db_user_iterate_by_name_eq(struct ort *ctx, user_cb cb, void *arg, const char *v1)
  549 {
  550 	struct user p;
  551 	const struct sqlbox_parmset *res;
  552 	struct sqlbox *db = ctx->db;
  553 	struct sqlbox_parm parms[1];
  554 
  555 	memset(parms, 0, sizeof(parms));
  556 	parms[0].sparm = v1;
  557 	parms[0].type = SQLBOX_PARM_STRING;
  558 
  559 	if (!sqlbox_prepare_bind_async
  560 	    (db, 0, STMT_user_BY_SEARCH_0,
  561 	     1, parms, SQLBOX_STMT_MULTI))
  562 		exit(EXIT_FAILURE);
  563 	while ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  564 		db_user_fill_r(ctx, &p, res, NULL);
  565 		(*cb)(&p, arg);
  566 		db_user_unfill_r(&p);
  567 	}
  568 	if (res == NULL)
  569 		exit(EXIT_FAILURE);
  570 	if (!sqlbox_finalise(db, 0))
  571 		exit(EXIT_FAILURE);
  572 }
  573 
  574 struct user *
  575 db_user_get_creds(struct ort *ctx, const char *v1, const char *v2)
  576 {
  577 	struct user *p = NULL;
  578 	const struct sqlbox_parmset *res;
  579 	struct sqlbox *db = ctx->db;
  580 	struct sqlbox_parm parms[1];
  581 
  582 	memset(parms, 0, sizeof(parms));
  583 	parms[0].sparm = v1;
  584 	parms[0].type = SQLBOX_PARM_STRING;
  585 
  586 	if (!sqlbox_prepare_bind_async
  587 	    (db, 0, STMT_user_BY_SEARCH_1, 1, parms, 0))
  588 		exit(EXIT_FAILURE);
  589 	if ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  590 		p = malloc(sizeof(struct user));
  591 		if (p == NULL) {
  592 			perror(NULL);
  593 			exit(EXIT_FAILURE);
  594 		}
  595 		db_user_fill_r(ctx, p, res, NULL);
  596 		if (v2 == NULL || crypt_checkpass(v2, p->hash) == -1) {
  597 			db_user_free(p);
  598 			p = NULL;
  599 		}
  600 	}
  601 	if (res == NULL)
  602 		exit(EXIT_FAILURE);
  603 	if (!sqlbox_finalise(db, 0))
  604 		exit(EXIT_FAILURE);
  605 	return p;
  606 }
  607 
  608 struct user *
  609 db_user_get_by_uid_eq(struct ort *ctx, user_uid v1)
  610 {
  611 	struct user *p = NULL;
  612 	const struct sqlbox_parmset *res;
  613 	struct sqlbox *db = ctx->db;
  614 	struct sqlbox_parm parms[1];
  615 
  616 	memset(parms, 0, sizeof(parms));
  617 	parms[0].iparm = ORT_GETV_user_uid(v1);
  618 	parms[0].type = SQLBOX_PARM_INT;
  619 
  620 	if (!sqlbox_prepare_bind_async
  621 	    (db, 0, STMT_user_BY_SEARCH_2, 1, parms, 0))
  622 		exit(EXIT_FAILURE);
  623 	if ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  624 		p = malloc(sizeof(struct user));
  625 		if (p == NULL) {
  626 			perror(NULL);
  627 			exit(EXIT_FAILURE);
  628 		}
  629 		db_user_fill_r(ctx, p, res, NULL);
  630 	}
  631 	if (res == NULL)
  632 		exit(EXIT_FAILURE);
  633 	if (!sqlbox_finalise(db, 0))
  634 		exit(EXIT_FAILURE);
  635 	return p;
  636 }
  637 
  638 int
  639 db_user_update_hash_set_by_uid_eq(struct ort *ctx, const char *v1, user_uid v2)
  640 {
  641 	enum sqlbox_code c;
  642 	struct sqlbox *db = ctx->db;
  643 	struct sqlbox_parm parms[2];
  644 	char hash1[64];
  645 
  646 	crypt_newhash(v1, "blowfish,a", hash1, sizeof(hash1));
  647 
  648 	memset(parms, 0, sizeof(parms));
  649 	parms[0].sparm = hash1;
  650 	parms[0].type = SQLBOX_PARM_STRING;
  651 	parms[1].iparm = ORT_GETV_user_uid(v2);
  652 	parms[1].type = SQLBOX_PARM_INT;
  653 
  654 	c = sqlbox_exec
  655 		(db, 0, STMT_user_UPDATE_0,
  656 		 2, parms, SQLBOX_STMT_CONSTRAINT);
  657 	if (c == SQLBOX_CODE_ERROR)
  658 		exit(EXIT_FAILURE);
  659 	return (c == SQLBOX_CODE_OK) ? 1 : 0;
  660 }
  661 
  662 int
  663 db_user_update_email_set_by_uid_eq(struct ort *ctx, const char *v1, user_uid v2)
  664 {
  665 	enum sqlbox_code c;
  666 	struct sqlbox *db = ctx->db;
  667 	struct sqlbox_parm parms[2];
  668 
  669 	memset(parms, 0, sizeof(parms));
  670 	parms[0].sparm = v1;
  671 	parms[0].type = SQLBOX_PARM_STRING;
  672 	parms[1].iparm = ORT_GETV_user_uid(v2);
  673 	parms[1].type = SQLBOX_PARM_INT;
  674 
  675 	c = sqlbox_exec
  676 		(db, 0, STMT_user_UPDATE_1,
  677 		 2, parms, SQLBOX_STMT_CONSTRAINT);
  678 	if (c == SQLBOX_CODE_ERROR)
  679 		exit(EXIT_FAILURE);
  680 	return (c == SQLBOX_CODE_OK) ? 1 : 0;
  681 }
  682 
  683 void
  684 db_user_delete(struct ort *ctx)
  685 {
  686 	enum sqlbox_code c;
  687 	struct sqlbox *db = ctx->db;
  688 
  689 
  690 	c = sqlbox_exec
  691 		(db, 0, STMT_user_DELETE_0, 0, NULL, 0);
  692 	if (c != SQLBOX_CODE_OK)
  693 		exit(EXIT_FAILURE);
  694 }
  695 
  696 /*
  697  * Fill in a session from an open statement "stmt".
  698  * This starts grabbing results from "pos", which may be NULL to start 
  699  * from zero.
  700  * This follows DB_SCHEMA_session's order for columns.
  701  */
  702 static void
  703 db_session_fill(struct ort *ctx, struct session *p, const struct sqlbox_parmset *set, size_t *pos)
  704 {
  705 	size_t i = 0;
  706 	int64_t tmpint;
  707 
  708 	if (pos == NULL)
  709 		pos = &i;
  710 	memset(p, 0, sizeof(*p));
  711 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  712 		exit(EXIT_FAILURE);
  713 	ORT_SET_session_userid(p, tmpint);
  714 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  715 		exit(EXIT_FAILURE);
  716 	ORT_SET_session_token(p, tmpint);
  717 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  718 		exit(EXIT_FAILURE);
  719 	ORT_SET_session_mtime(p, (time_t)tmpint);
  720 	if (sqlbox_parm_int(&set->ps[(*pos)++], &tmpint) == -1)
  721 		exit(EXIT_FAILURE);
  722 	ORT_SET_session_id(p, tmpint);
  723 }
  724 
  725 static void
  726 db_session_fill_r(struct ort *ctx, struct session *p,
  727 	const struct sqlbox_parmset *res, size_t *pos)
  728 {
  729 	size_t i = 0;
  730 
  731 	if (pos == NULL)
  732 		pos = &i;
  733 	db_session_fill(ctx, p, res, pos);
  734 	db_user_fill_r(ctx, &p->user, res, pos);
  735 }
  736 
  737 /*
  738  * Free resources from "p" and all nested objects.
  739  * Does not free the "p" pointer itself.
  740  * Has no effect if "p" is NULL.
  741  */
  742 static void
  743 db_session_unfill(struct session *p)
  744 {
  745 	if (p == NULL)
  746 		return;
  747 }
  748 
  749 static void
  750 db_session_unfill_r(struct session *p)
  751 {
  752 	if (p == NULL)
  753 		return;
  754 	db_session_unfill(p);
  755 	db_user_unfill_r(&p->user);
  756 }
  757 
  758 void
  759 db_session_free(struct session *p)
  760 {
  761 	db_session_unfill_r(p);
  762 	free(p);
  763 }
  764 
  765 int64_t
  766 db_session_insert(struct ort *ctx, user_uid v1, session_token v2, session_mtime v3)
  767 {
  768 	enum sqlbox_code rc;
  769 	int64_t id = -1;
  770 	struct sqlbox *db = ctx->db;
  771 	struct sqlbox_parm parms[3];
  772 
  773 	memset(parms, 0, sizeof(parms));
  774 	parms[0].iparm = ORT_GETV_session_userid(v1);
  775 	parms[0].type = SQLBOX_PARM_INT;
  776 	parms[1].iparm = ORT_GETV_session_token(v2);
  777 	parms[1].type = SQLBOX_PARM_INT;
  778 	parms[2].iparm = (time_t)ORT_GETV_session_mtime(v3);
  779 	parms[2].type = SQLBOX_PARM_INT;
  780 
  781 	rc = sqlbox_exec(db, 0, STMT_session_INSERT, 
  782 	     3, parms, SQLBOX_STMT_CONSTRAINT);
  783 	if (rc == SQLBOX_CODE_ERROR)
  784 		exit(EXIT_FAILURE);
  785 	else if (rc != SQLBOX_CODE_OK)
  786 		return (-1);
  787 	if (!sqlbox_lastid(db, 0, &id))
  788 		exit(EXIT_FAILURE);
  789 	return id;
  790 }
  791 
  792 void
  793 db_session_iterate_foo(struct ort *ctx, session_cb cb, void *arg, const char *v1,
  794      session_mtime v2)
  795 {
  796 	struct session p;
  797 	const struct sqlbox_parmset *res;
  798 	struct sqlbox *db = ctx->db;
  799 	struct sqlbox_parm parms[2];
  800 
  801 	memset(parms, 0, sizeof(parms));
  802 	parms[0].sparm = v1;
  803 	parms[0].type = SQLBOX_PARM_STRING;
  804 	parms[1].iparm = (time_t)ORT_GETV_session_mtime(v2);
  805 	parms[1].type = SQLBOX_PARM_INT;
  806 
  807 	if (!sqlbox_prepare_bind_async
  808 	    (db, 0, STMT_session_BY_SEARCH_0,
  809 	     2, parms, SQLBOX_STMT_MULTI))
  810 		exit(EXIT_FAILURE);
  811 	while ((res = sqlbox_step(db, 0)) != NULL && res->psz) {
  812 		db_session_fill_r(ctx, &p, res, NULL);
  813 		(*cb)(&p, arg);
  814 		db_session_unfill_r(&p);
  815 	}
  816 	if (res == NULL)
  817 		exit(EXIT_FAILURE);
  818 	if (!sqlbox_finalise(db, 0))
  819 		exit(EXIT_FAILURE);
  820 }
  821 
  822 void
  823 db_session_delete_by_id_eq(struct ort *ctx, session_id v1)
  824 {
  825 	enum sqlbox_code c;
  826 	struct sqlbox *db = ctx->db;
  827 	struct sqlbox_parm parms[1];
  828 
  829 	memset(parms, 0, sizeof(parms));
  830 	parms[0].iparm = ORT_GETV_session_id(v1);
  831 	parms[0].type = SQLBOX_PARM_INT;
  832 
  833 	c = sqlbox_exec
  834 		(db, 0, STMT_session_DELETE_0, 1, parms, 0);
  835 	if (c != SQLBOX_CODE_OK)
  836 		exit(EXIT_FAILURE);
  837 }
  838