diff --git a/contrib/txid/expected/txid.out b/contrib/txid/expected/txid.out
index c0220bb525cceb81f6ed4a1ba691aed39fefccff..1b0da20b5f698a3a05c5969c145af8142851dcaf 100644
--- a/contrib/txid/expected/txid.out
+++ b/contrib/txid/expected/txid.out
@@ -8,18 +8,18 @@ select '12:13:'::txid_snapshot;
 (1 row)
 
 select '12:13:1,2'::txid_snapshot;
-ERROR:  illegal txid_snapshot input format
+ERROR:  invalid input for txid_snapshot: "12:13:1,2"
 -- errors
 select '31:12:'::txid_snapshot;
-ERROR:  illegal txid_snapshot input format
+ERROR:  invalid input for txid_snapshot: "31:12:"
 select '0:1:'::txid_snapshot;
-ERROR:  illegal txid_snapshot input format
+ERROR:  invalid input for txid_snapshot: "0:1:"
 select '12:13:0'::txid_snapshot;
-ERROR:  illegal txid_snapshot input format
+ERROR:  invalid input for txid_snapshot: "12:13:0"
 select '12:16:14,13'::txid_snapshot;
-ERROR:  illegal txid_snapshot input format
+ERROR:  invalid input for txid_snapshot: "12:16:14,13"
 select '12:16:14,14'::txid_snapshot;
-ERROR:  illegal txid_snapshot input format
+ERROR:  invalid input for txid_snapshot: "12:16:14,14"
 create table snapshot_test (
 	nr	integer,
 	snap	txid_snapshot
@@ -210,3 +210,12 @@ select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010
  t
 (1 row)
 
+-- test 64bit overflow
+SELECT txid_snapshot '1:9223372036854775807:3';
+      txid_snapshot      
+-------------------------
+ 1:9223372036854775807:3
+(1 row)
+
+SELECT txid_snapshot '1:9223372036854775808:3';
+ERROR:  invalid input for txid_snapshot: "1:9223372036854775808:3"
diff --git a/contrib/txid/sql/txid.sql b/contrib/txid/sql/txid.sql
index b86bfffb050dbeaaed39a483683d772acff6b235..efedb86bfac9dce0738f961de958621fd3c3f10c 100644
--- a/contrib/txid/sql/txid.sql
+++ b/contrib/txid/sql/txid.sql
@@ -56,3 +56,6 @@ select txid_snapshot '1000100010001000:1000100010001100:1000100010001012,1000100
 select txid_visible_in_snapshot('1000100010001012', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
 select txid_visible_in_snapshot('1000100010001015', '1000100010001000:1000100010001100:1000100010001012,1000100010001013');
 
+-- test 64bit overflow
+SELECT txid_snapshot '1:9223372036854775807:3';
+SELECT txid_snapshot '1:9223372036854775808:3';
diff --git a/contrib/txid/txid.c b/contrib/txid/txid.c
index 8a4b5e797baee086f45c2ba5485bb2fbd2d6f1b8..606fb40040bf4a522d799302bb6dcf8ef7d0268d 100644
--- a/contrib/txid/txid.c
+++ b/contrib/txid/txid.c
@@ -225,6 +225,39 @@ buf_finalize(StringInfo buf)
 	return snap;
 }
 
+/*
+ * simple number parser.
+ *
+ * We return 0 on error, which is invalid value for txid.
+ */
+static txid
+str2txid(const char *s, const char **endp)
+{
+	txid val = 0;
+
+	for (; *s; s++)
+	{
+		txid last = val;
+
+		if (*s < '0' || *s > '9')
+			break;
+
+		val = val * 10 + (*s - '0');
+
+		/*
+		 * check for overflow
+		 */
+		if (val > MAX_TXID || (val / 10) != last)
+		{
+			val = 0;
+			break;
+		}
+	}
+	if (endp)
+		*endp = s;
+	return val;
+}
+
 /*
  * parse snapshot from cstring
  */
@@ -234,21 +267,22 @@ parse_snapshot(const char *str)
 	txid		xmin;
 	txid		xmax;
 	txid		last_val = 0, val;
-	char	   *endp;
+	const char *str_start = str;
+	const char *endp;
 	StringInfo  buf;
 
-	xmin = (txid) strtoull(str, &endp, 0);
+	xmin = str2txid(str, &endp);
 	if (*endp != ':')
 		goto bad_format;
 	str = endp + 1;
 
-	xmax = (txid) strtoull(str, &endp, 0);
+	xmax = str2txid(str, &endp);
 	if (*endp != ':')
 		goto bad_format;
 	str = endp + 1;
 
 	/* it should look sane */
-	if (xmin > xmax || xmin == 0 || xmax > MAX_TXID)
+	if (xmin == 0 || xmax == 0 || xmin > xmax)
 		goto bad_format;
 
 	/* allocate buffer */
@@ -258,11 +292,11 @@ parse_snapshot(const char *str)
 	while (*str != '\0')
 	{
 		/* read next value */
-		val = (txid) strtoull(str, &endp, 0);
+		val = str2txid(str, &endp);
 		str = endp;
 
 		/* require the input to be in order */
-		if (val < xmin || val <= last_val || val >= xmax)
+		if (val < xmin || val >= xmax || val <= last_val)
 			goto bad_format;
 		
 		buf_add_txid(buf, val);
@@ -277,7 +311,7 @@ parse_snapshot(const char *str)
 	return buf_finalize(buf);
 
 bad_format:
-	elog(ERROR, "illegal txid_snapshot input format");
+	elog(ERROR, "invalid input for txid_snapshot: \"%s\"", str_start);
 	return NULL;
 }