>From 7659ff0b8f2b0551aafc41442f0c84e987790b4b Mon Sep 17 00:00:00 2001 From: Tim Chase Date: Thu, 15 Oct 2020 18:02:45 -0500 Subject: [PATCH 1/3] Add OUTER JOIN functionality --- src/rec-db.c | 36 ++++++++++++++++++++++++++++++++---- src/rec.h | 22 +++++++++++++++++----- utils/recsel.c | 18 ++++++++++++++---- 3 files changed, 63 insertions(+), 13 deletions(-) diff --git a/src/rec-db.c b/src/rec-db.c index 26229be..f9ad806 100644 --- a/src/rec-db.c +++ b/src/rec-db.c @@ -72,7 +72,7 @@ static bool rec_db_set_act_set (rec_rset_t rset, rec_record_t record, rec_fex_t static bool rec_db_set_act_add (rec_rset_t rset, rec_record_t record, rec_fex_t fex, const char *arg); static bool rec_db_set_act_delete (rec_rset_t rset, rec_record_t record, rec_fex_t fex, bool comment_out); -static rec_rset_t rec_db_join (rec_db_t db, const char *type1, const char *field, const char *type2); +static rec_rset_t rec_db_join (rec_db_t db, const char *type1, const char *field, const char *type2, enum rec_join_type_e join_type); static rec_record_t rec_db_merge_records (rec_record_t record1, rec_record_t record2, const char *prefix); /* @@ -268,6 +268,7 @@ rec_rset_t rec_db_query (rec_db_t db, const char *type, const char *join, + enum rec_join_type_e join_type, size_t *index, rec_sex_t sex, const char *fast_string, @@ -332,7 +333,11 @@ rec_db_query (rec_db_t db, if (rec_db_get_rset_by_type (db, referred_type)) { - rset = rec_db_join (db, type, join, referred_type); + rset = rec_db_join (db, + type, + join, + referred_type, + join_type); if (!rset) { /* Out of memory. */ @@ -1040,7 +1045,9 @@ static rec_rset_t rec_db_join (rec_db_t db, const char *type1, const char *field, - const char *type2) + const char *type2, + enum rec_join_type_e join_type + ) { /* Note that this function is inefficient like hell. */ @@ -1055,7 +1062,12 @@ rec_db_join (rec_db_t db, rec_rset_t rset2 = rec_db_get_rset_by_type (db, type2); - if (!rset1 || !rset2) + if (!rset1) + { + return NULL; + } + + if (join_type == REC_JOIN_INNER && !rset2) { return NULL; } @@ -1124,6 +1136,22 @@ rec_db_join (rec_db_t db, if (!found) { /* Skip this combination record. */ + if (join_type == REC_JOIN_OUTER) + { + /* but this is an OUTER JOIN so keep the original */ + rec_record_t record = NULL; + record = rec_record_dup (record1); + if (!record) + { + return NULL; + } + rec_record_set_container (record, join); + if (!rec_mset_append (rec_rset_mset (join), MSET_RECORD, (void *) record, MSET_ANY)) + { + /* Out of memory. */ + return NULL; + } + } continue; } diff --git a/src/rec.h b/src/rec.h index 3d6168b..aef415a 100644 --- a/src/rec.h +++ b/src/rec.h @@ -1391,11 +1391,14 @@ rec_aggregate_reg_t rec_db_aggregates (rec_db_t db); JOIN - If not NULL, this argument must be a string denoting a field - name. This field name must be a foreign key (field of type - 'rec') defined in the selected record set. The query operation - will do an inner join using T1.Field = T2.Field as join - criteria. + If not NULL, this argument must be a string denoting a field name. + This field name must be a foreign key (field of type 'rec') + defined in the selected record set. The query operation will do + an join using T1.Field = T2.Field as join criteria. + + JOINTYPE + + Either JOIN_INNER or JOIN_OUTER to control how the JOIN happens INDEX @@ -1484,9 +1487,18 @@ rec_aggregate_reg_t rec_db_aggregates (rec_db_t db); #define REC_Q_NOINDEX ((size_t)-1) +enum rec_join_type_e + { + /* An inner join. */ + REC_JOIN_INNER = 0, + /* An outer join. */ + REC_JOIN_OUTER + }; + rec_rset_t rec_db_query (rec_db_t db, const char *type, const char *join, + enum rec_join_type_e join_type, size_t *index, rec_sex_t sex, const char *fast_string, diff --git a/utils/recsel.c b/utils/recsel.c index a914bd1..4a62646 100644 --- a/utils/recsel.c +++ b/utils/recsel.c @@ -61,6 +61,7 @@ char *recsel_password = NULL; bool recsel_uniq = false; size_t recutl_random = 0; char *recsel_join = NULL; +int recsel_join_type = 0; /* * Command line options management. @@ -83,7 +84,8 @@ enum #endif UNIQ_ARG, GROUP_BY_ARG, - JOIN_ARG + JOIN_INNER_ARG, + JOIN_OUTER_ARG }; static const struct option GNU_longOptions[] = @@ -103,7 +105,9 @@ static const struct option GNU_longOptions[] = #endif {"uniq", no_argument, NULL, UNIQ_ARG}, {"group-by", required_argument, NULL, GROUP_BY_ARG}, - {"join", required_argument, NULL, JOIN_ARG}, + {"join", required_argument, NULL, JOIN_INNER_ARG}, + {"inner-join", required_argument, NULL, JOIN_INNER_ARG}, + {"outer-join", required_argument, NULL, JOIN_OUTER_ARG}, {NULL, 0, NULL, 0} }; @@ -189,7 +193,7 @@ recsel_parse_args (int argc, argv, RECORD_SELECTION_SHORT_ARGS ENCRYPTION_SHORT_ARGS - "S:Cdcp:P:R:UG:j:", + "S:Cdcp:P:R:UG:j:J:", GNU_longOptions, NULL)) != -1) { @@ -251,8 +255,10 @@ recsel_parse_args (int argc, break; } - case JOIN_ARG: + case JOIN_INNER_ARG: + case JOIN_OUTER_ARG: case 'j': + case 'J': { if (recsel_join) { @@ -265,6 +271,9 @@ recsel_parse_args (int argc, } recsel_join = xstrdup (optarg); + recsel_join_type = ('j' == c || JOIN_INNER_ARG == c) + ? REC_JOIN_INNER + : REC_JOIN_OUTER; break; } case GROUP_BY_ARG: @@ -465,6 +474,7 @@ recsel_process_data (rec_db_t db) rset = rec_db_query (db, recutl_type, recsel_join, + recsel_join_type, recutl_index(), recutl_sex, recutl_quick_str, -- 2.25.1