mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 10:30:33 +03:00 
			
		
		
		
	The affected functions are: bsearch, memcmp, memcpy, memset, memmove, qsort, repalloc Reviewed-by: Corey Huinker <corey.huinker@gmail.com> Discussion: https://www.postgresql.org/message-id/flat/fd9adf5d-b1aa-e82f-e4c7-263c30145807%40enterprisedb.com
		
			
				
	
	
		
			411 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			411 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|  * contrib/intarray/_int_tool.c
 | |
|  */
 | |
| #include "postgres.h"
 | |
| 
 | |
| #include <limits.h>
 | |
| 
 | |
| #include "_int.h"
 | |
| #include "catalog/pg_type.h"
 | |
| #include "lib/qunique.h"
 | |
| 
 | |
| /* arguments are assumed sorted & unique-ified */
 | |
| bool
 | |
| inner_int_contains(ArrayType *a, ArrayType *b)
 | |
| {
 | |
| 	int			na,
 | |
| 				nb;
 | |
| 	int			i,
 | |
| 				j,
 | |
| 				n;
 | |
| 	int		   *da,
 | |
| 			   *db;
 | |
| 
 | |
| 	na = ARRNELEMS(a);
 | |
| 	nb = ARRNELEMS(b);
 | |
| 	da = ARRPTR(a);
 | |
| 	db = ARRPTR(b);
 | |
| 
 | |
| 	i = j = n = 0;
 | |
| 	while (i < na && j < nb)
 | |
| 	{
 | |
| 		if (da[i] < db[j])
 | |
| 			i++;
 | |
| 		else if (da[i] == db[j])
 | |
| 		{
 | |
| 			n++;
 | |
| 			i++;
 | |
| 			j++;
 | |
| 		}
 | |
| 		else
 | |
| 			break;				/* db[j] is not in da */
 | |
| 	}
 | |
| 
 | |
| 	return (n == nb);
 | |
| }
 | |
| 
 | |
| /* arguments are assumed sorted */
 | |
| bool
 | |
| inner_int_overlap(ArrayType *a, ArrayType *b)
 | |
| {
 | |
| 	int			na,
 | |
| 				nb;
 | |
| 	int			i,
 | |
| 				j;
 | |
| 	int		   *da,
 | |
| 			   *db;
 | |
| 
 | |
| 	na = ARRNELEMS(a);
 | |
| 	nb = ARRNELEMS(b);
 | |
| 	da = ARRPTR(a);
 | |
| 	db = ARRPTR(b);
 | |
| 
 | |
| 	i = j = 0;
 | |
| 	while (i < na && j < nb)
 | |
| 	{
 | |
| 		if (da[i] < db[j])
 | |
| 			i++;
 | |
| 		else if (da[i] == db[j])
 | |
| 			return true;
 | |
| 		else
 | |
| 			j++;
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| inner_int_union(ArrayType *a, ArrayType *b)
 | |
| {
 | |
| 	ArrayType  *r = NULL;
 | |
| 
 | |
| 	CHECKARRVALID(a);
 | |
| 	CHECKARRVALID(b);
 | |
| 
 | |
| 	if (ARRISEMPTY(a) && ARRISEMPTY(b))
 | |
| 		return new_intArrayType(0);
 | |
| 	if (ARRISEMPTY(a))
 | |
| 		r = copy_intArrayType(b);
 | |
| 	if (ARRISEMPTY(b))
 | |
| 		r = copy_intArrayType(a);
 | |
| 
 | |
| 	if (!r)
 | |
| 	{
 | |
| 		int			na = ARRNELEMS(a),
 | |
| 					nb = ARRNELEMS(b);
 | |
| 		int		   *da = ARRPTR(a),
 | |
| 				   *db = ARRPTR(b);
 | |
| 		int			i,
 | |
| 					j,
 | |
| 				   *dr;
 | |
| 
 | |
| 		r = new_intArrayType(na + nb);
 | |
| 		dr = ARRPTR(r);
 | |
| 
 | |
| 		/* union */
 | |
| 		i = j = 0;
 | |
| 		while (i < na && j < nb)
 | |
| 		{
 | |
| 			if (da[i] == db[j])
 | |
| 			{
 | |
| 				*dr++ = da[i++];
 | |
| 				j++;
 | |
| 			}
 | |
| 			else if (da[i] < db[j])
 | |
| 				*dr++ = da[i++];
 | |
| 			else
 | |
| 				*dr++ = db[j++];
 | |
| 		}
 | |
| 
 | |
| 		while (i < na)
 | |
| 			*dr++ = da[i++];
 | |
| 		while (j < nb)
 | |
| 			*dr++ = db[j++];
 | |
| 
 | |
| 		r = resize_intArrayType(r, dr - ARRPTR(r));
 | |
| 	}
 | |
| 
 | |
| 	if (ARRNELEMS(r) > 1)
 | |
| 		r = _int_unique(r);
 | |
| 
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| inner_int_inter(ArrayType *a, ArrayType *b)
 | |
| {
 | |
| 	ArrayType  *r;
 | |
| 	int			na,
 | |
| 				nb;
 | |
| 	int		   *da,
 | |
| 			   *db,
 | |
| 			   *dr;
 | |
| 	int			i,
 | |
| 				j,
 | |
| 				k;
 | |
| 
 | |
| 	if (ARRISEMPTY(a) || ARRISEMPTY(b))
 | |
| 		return new_intArrayType(0);
 | |
| 
 | |
| 	na = ARRNELEMS(a);
 | |
| 	nb = ARRNELEMS(b);
 | |
| 	da = ARRPTR(a);
 | |
| 	db = ARRPTR(b);
 | |
| 	r = new_intArrayType(Min(na, nb));
 | |
| 	dr = ARRPTR(r);
 | |
| 
 | |
| 	i = j = k = 0;
 | |
| 	while (i < na && j < nb)
 | |
| 	{
 | |
| 		if (da[i] < db[j])
 | |
| 			i++;
 | |
| 		else if (da[i] == db[j])
 | |
| 		{
 | |
| 			if (k == 0 || dr[k - 1] != db[j])
 | |
| 				dr[k++] = db[j];
 | |
| 			i++;
 | |
| 			j++;
 | |
| 		}
 | |
| 		else
 | |
| 			j++;
 | |
| 	}
 | |
| 
 | |
| 	if (k == 0)
 | |
| 	{
 | |
| 		pfree(r);
 | |
| 		return new_intArrayType(0);
 | |
| 	}
 | |
| 	else
 | |
| 		return resize_intArrayType(r, k);
 | |
| }
 | |
| 
 | |
| void
 | |
| rt__int_size(ArrayType *a, float *size)
 | |
| {
 | |
| 	*size = (float) ARRNELEMS(a);
 | |
| }
 | |
| 
 | |
| /* qsort_arg comparison function for isort() */
 | |
| static int
 | |
| isort_cmp(const void *a, const void *b, void *arg)
 | |
| {
 | |
| 	int32		aval = *((const int32 *) a);
 | |
| 	int32		bval = *((const int32 *) b);
 | |
| 
 | |
| 	if (aval < bval)
 | |
| 		return -1;
 | |
| 	if (aval > bval)
 | |
| 		return 1;
 | |
| 
 | |
| 	/*
 | |
| 	 * Report if we have any duplicates.  If there are equal keys, qsort must
 | |
| 	 * compare them at some point, else it wouldn't know whether one should go
 | |
| 	 * before or after the other.
 | |
| 	 */
 | |
| 	*((bool *) arg) = true;
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| /* Sort the given data (len >= 2).  Return true if any duplicates found */
 | |
| bool
 | |
| isort(int32 *a, int len)
 | |
| {
 | |
| 	bool		r = false;
 | |
| 
 | |
| 	qsort_arg(a, len, sizeof(int32), isort_cmp, &r);
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| /* Create a new int array with room for "num" elements */
 | |
| ArrayType *
 | |
| new_intArrayType(int num)
 | |
| {
 | |
| 	ArrayType  *r;
 | |
| 	int			nbytes;
 | |
| 
 | |
| 	/* if no elements, return a zero-dimensional array */
 | |
| 	if (num <= 0)
 | |
| 	{
 | |
| 		Assert(num == 0);
 | |
| 		r = construct_empty_array(INT4OID);
 | |
| 		return r;
 | |
| 	}
 | |
| 
 | |
| 	nbytes = ARR_OVERHEAD_NONULLS(1) + sizeof(int) * num;
 | |
| 
 | |
| 	r = (ArrayType *) palloc0(nbytes);
 | |
| 
 | |
| 	SET_VARSIZE(r, nbytes);
 | |
| 	ARR_NDIM(r) = 1;
 | |
| 	r->dataoffset = 0;			/* marker for no null bitmap */
 | |
| 	ARR_ELEMTYPE(r) = INT4OID;
 | |
| 	ARR_DIMS(r)[0] = num;
 | |
| 	ARR_LBOUND(r)[0] = 1;
 | |
| 
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| resize_intArrayType(ArrayType *a, int num)
 | |
| {
 | |
| 	int			nbytes;
 | |
| 	int			i;
 | |
| 
 | |
| 	/* if no elements, return a zero-dimensional array */
 | |
| 	if (num <= 0)
 | |
| 	{
 | |
| 		Assert(num == 0);
 | |
| 		a = construct_empty_array(INT4OID);
 | |
| 		return a;
 | |
| 	}
 | |
| 
 | |
| 	if (num == ARRNELEMS(a))
 | |
| 		return a;
 | |
| 
 | |
| 	nbytes = ARR_DATA_OFFSET(a) + sizeof(int) * num;
 | |
| 
 | |
| 	a = (ArrayType *) repalloc(a, nbytes);
 | |
| 
 | |
| 	SET_VARSIZE(a, nbytes);
 | |
| 	/* usually the array should be 1-D already, but just in case ... */
 | |
| 	for (i = 0; i < ARR_NDIM(a); i++)
 | |
| 	{
 | |
| 		ARR_DIMS(a)[i] = num;
 | |
| 		num = 1;
 | |
| 	}
 | |
| 	return a;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| copy_intArrayType(ArrayType *a)
 | |
| {
 | |
| 	ArrayType  *r;
 | |
| 	int			n = ARRNELEMS(a);
 | |
| 
 | |
| 	r = new_intArrayType(n);
 | |
| 	memcpy(ARRPTR(r), ARRPTR(a), n * sizeof(int32));
 | |
| 	return r;
 | |
| }
 | |
| 
 | |
| /* num for compressed key */
 | |
| int
 | |
| internal_size(int *a, int len)
 | |
| {
 | |
| 	int			i;
 | |
| 	int64		size = 0;
 | |
| 
 | |
| 	for (i = 0; i < len; i += 2)
 | |
| 	{
 | |
| 		if (!i || a[i] != a[i - 1]) /* do not count repeated range */
 | |
| 			size += (int64) (a[i + 1]) - (int64) (a[i]) + 1;
 | |
| 	}
 | |
| 
 | |
| 	if (size > (int64) INT_MAX || size < (int64) INT_MIN)
 | |
| 		return -1;				/* overflow */
 | |
| 	return (int) size;
 | |
| }
 | |
| 
 | |
| /* unique-ify elements of r in-place ... r must be sorted already */
 | |
| ArrayType *
 | |
| _int_unique(ArrayType *r)
 | |
| {
 | |
| 	int			num = ARRNELEMS(r);
 | |
| 	bool		duplicates_found;	/* not used */
 | |
| 
 | |
| 	num = qunique_arg(ARRPTR(r), num, sizeof(int), isort_cmp,
 | |
| 					  &duplicates_found);
 | |
| 
 | |
| 	return resize_intArrayType(r, num);
 | |
| }
 | |
| 
 | |
| void
 | |
| gensign(BITVECP sign, int *a, int len, int siglen)
 | |
| {
 | |
| 	int			i;
 | |
| 
 | |
| 	/* we assume that the sign vector is previously zeroed */
 | |
| 	for (i = 0; i < len; i++)
 | |
| 	{
 | |
| 		HASH(sign, *a, siglen);
 | |
| 		a++;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| int32
 | |
| intarray_match_first(ArrayType *a, int32 elem)
 | |
| {
 | |
| 	int32	   *aa,
 | |
| 				c,
 | |
| 				i;
 | |
| 
 | |
| 	CHECKARRVALID(a);
 | |
| 	c = ARRNELEMS(a);
 | |
| 	aa = ARRPTR(a);
 | |
| 	for (i = 0; i < c; i++)
 | |
| 		if (aa[i] == elem)
 | |
| 			return (i + 1);
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| intarray_add_elem(ArrayType *a, int32 elem)
 | |
| {
 | |
| 	ArrayType  *result;
 | |
| 	int32	   *r;
 | |
| 	int32		c;
 | |
| 
 | |
| 	CHECKARRVALID(a);
 | |
| 	c = ARRNELEMS(a);
 | |
| 	result = new_intArrayType(c + 1);
 | |
| 	r = ARRPTR(result);
 | |
| 	if (c > 0)
 | |
| 		memcpy(r, ARRPTR(a), c * sizeof(int32));
 | |
| 	r[c] = elem;
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| intarray_concat_arrays(ArrayType *a, ArrayType *b)
 | |
| {
 | |
| 	ArrayType  *result;
 | |
| 	int32		ac = ARRNELEMS(a);
 | |
| 	int32		bc = ARRNELEMS(b);
 | |
| 
 | |
| 	CHECKARRVALID(a);
 | |
| 	CHECKARRVALID(b);
 | |
| 	result = new_intArrayType(ac + bc);
 | |
| 	if (ac)
 | |
| 		memcpy(ARRPTR(result), ARRPTR(a), ac * sizeof(int32));
 | |
| 	if (bc)
 | |
| 		memcpy(ARRPTR(result) + ac, ARRPTR(b), bc * sizeof(int32));
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| ArrayType *
 | |
| int_to_intset(int32 elem)
 | |
| {
 | |
| 	ArrayType  *result;
 | |
| 	int32	   *aa;
 | |
| 
 | |
| 	result = new_intArrayType(1);
 | |
| 	aa = ARRPTR(result);
 | |
| 	aa[0] = elem;
 | |
| 	return result;
 | |
| }
 | |
| 
 | |
| int
 | |
| compASC(const void *a, const void *b)
 | |
| {
 | |
| 	if (*(const int32 *) a == *(const int32 *) b)
 | |
| 		return 0;
 | |
| 	return (*(const int32 *) a > *(const int32 *) b) ? 1 : -1;
 | |
| }
 | |
| 
 | |
| int
 | |
| compDESC(const void *a, const void *b)
 | |
| {
 | |
| 	if (*(const int32 *) a == *(const int32 *) b)
 | |
| 		return 0;
 | |
| 	return (*(const int32 *) a < *(const int32 *) b) ? 1 : -1;
 | |
| }
 |