diff --git a/contrib/ltree/expected/ltree.out b/contrib/ltree/expected/ltree.out
index 7e51ce3e2ba..fef2d40f173 100644
--- a/contrib/ltree/expected/ltree.out
+++ b/contrib/ltree/expected/ltree.out
@@ -251,6 +251,24 @@ SELECT lca('{1.2.3,1.2.3.4.5.6}');
1.2
(1 row)
+SELECT lca('{1.2.3}');
+ lca
+-----
+ 1.2
+(1 row)
+
+SELECT lca('{1}'), lca('{1}') IS NULL;
+ lca | ?column?
+-----+----------
+ | f
+(1 row)
+
+SELECT lca('{}') IS NULL;
+ ?column?
+----------
+ t
+(1 row)
+
SELECT lca('1.la.2.3','1.2.3.4.5.6');
lca
-----
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;
diff --git a/contrib/ltree/sql/ltree.sql b/contrib/ltree/sql/ltree.sql
index eb1beaef31f..4dbc14d67a3 100644
--- a/contrib/ltree/sql/ltree.sql
+++ b/contrib/ltree/sql/ltree.sql
@@ -49,6 +49,9 @@ SELECT lca('{la.2.3,1.2.3.4.5.6,""}') IS NULL;
SELECT lca('{la.2.3,1.2.3.4.5.6}') IS NULL;
SELECT lca('{1.la.2.3,1.2.3.4.5.6}');
SELECT lca('{1.2.3,1.2.3.4.5.6}');
+SELECT lca('{1.2.3}');
+SELECT lca('{1}'), lca('{1}') IS NULL;
+SELECT lca('{}') IS NULL;
SELECT lca('1.la.2.3','1.2.3.4.5.6');
SELECT lca('1.2.3','1.2.3.4.5.6');
SELECT lca('1.2.2.3','1.2.3.4.5.6');
diff --git a/doc/src/sgml/ltree.sgml b/doc/src/sgml/ltree.sgml
index c2d9ed32ce0..61b9ae0cc8d 100644
--- a/doc/src/sgml/ltree.sgml
+++ b/doc/src/sgml/ltree.sgml
@@ -457,17 +457,17 @@ Europe & Russia*@ & !Transportation
lca(ltree, ltree, ...)lca
ltree
- lowest common ancestor, i.e., longest common prefix of paths
+ longest common ancestor of paths
(up to 8 arguments supported)
- lca('1.2.2.3','1.2.3.4.5.6')
+ lca('1.2.3','1.2.3.4.5.6')
1.2
lca(ltree[])
ltree
- lowest common ancestor, i.e., longest common prefix of paths
- lca(array['1.2.2.3'::ltree,'1.2.3'])
+ longest common ancestor of paths in array
+ lca(array['1.2.3'::ltree,'1.2.3.4'])
1.2