diff options
Diffstat (limited to 'contrib/ltree/ltree_op.c')
-rw-r--r-- | contrib/ltree/ltree_op.c | 34 |
1 files changed, 25 insertions, 9 deletions
diff --git a/contrib/ltree/ltree_op.c b/contrib/ltree/ltree_op.c index aa1e9918bef..cb59d21ced4 100644 --- a/contrib/ltree/ltree_op.c +++ b/contrib/ltree/ltree_op.c @@ -402,22 +402,34 @@ ltree_textadd(PG_FUNCTION_ARGS) PG_RETURN_POINTER(r); } +/* + * Common code for variants of lca(), find longest common ancestor of inputs + * + * Returns NULL if there is no common ancestor, ie, the longest common + * prefix is empty. + */ ltree * lca_inner(ltree **a, int len) { int tmp, - num = ((*a)->numlevel) ? (*a)->numlevel - 1 : 0; - ltree **ptr = a + 1; - int i, - reslen = LTREE_HDRSIZE; + num, + i, + reslen; + ltree **ptr; ltree_level *l1, *l2; ltree *res; - + if (len <= 0) + return NULL; /* no inputs? */ if ((*a)->numlevel == 0) - return NULL; + return NULL; /* any empty input means NULL result */ + + /* num is the length of the longest common ancestor so far */ + num = (*a)->numlevel - 1; + /* Compare each additional input to *a */ + ptr = a + 1; while (ptr - a < len) { if ((*ptr)->numlevel == 0) @@ -428,11 +440,12 @@ lca_inner(ltree **a, int len) { l1 = LTREE_FIRST(*a); l2 = LTREE_FIRST(*ptr); - tmp = num; + tmp = Min(num, (*ptr)->numlevel - 1); num = 0; - for (i = 0; i < Min(tmp, (*ptr)->numlevel - 1); i++) + for (i = 0; i < tmp; i++) { - if (l1->len == l2->len && memcmp(l1->name, l2->name, l1->len) == 0) + if (l1->len == l2->len && + memcmp(l1->name, l2->name, l1->len) == 0) num = i + 1; else break; @@ -443,6 +456,8 @@ lca_inner(ltree **a, int len) ptr++; } + /* Now compute size of result ... */ + reslen = LTREE_HDRSIZE; l1 = LTREE_FIRST(*a); for (i = 0; i < num; i++) { @@ -450,6 +465,7 @@ lca_inner(ltree **a, int len) l1 = LEVEL_NEXT(l1); } + /* ... and construct it by copying from *a */ res = (ltree *) palloc0(reslen); SET_VARSIZE(res, reslen); res->numlevel = num; |