aboutsummaryrefslogtreecommitdiff
path: root/contrib/ltree/ltree_op.c
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/ltree/ltree_op.c')
-rw-r--r--contrib/ltree/ltree_op.c34
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;