1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +03:00

August 6, 2002

1. Reworked patch from Andrey Oktyabrski (ano@spider.ru) with
      functions: icount, sort, sort_asc, uniq, idx, subarray
      operations: #, +, -, |, &

FUNCTIONS:

  int   icount(int[]) - the number of elements in intarray
  int[] sort(int[], 'asc' | 'desc') - sort intarray
  int[] sort(int[]) - sort in ascending order
  int[] sort_asc(int[]),sort_desc(int[]) - shortcuts for sort
  int[] uniq(int[]) - returns unique elements
  int   idx(int[], int item) - returns index of first intarray matching element
                               to item, or '0' if matching failed.
  int[] subarray(int[],int START [, int LEN]) - returns part of intarray
                               starting from element number START (from 1)
                               and length LEN.
OPERATIONS:

  int[] && int[]  - overlap - returns TRUE if arrays has at least one common elements.
  int[] @  int[]  - contains - returns TRUE if left array contains right array
  int[] ~ int[]   - contained - returns TRUE if left array is contained in right array
  # int[]         - return the number of elements in array
  int[] + int     - push element to array ( add to end of array)
  int[] + int[]   - merge of arrays (right array added to the end of left one)
  int[] - int     - remove entries matched by right argument from array
  int[] - int[]   - remove left array from right
  int[] | int     - returns intarray - union of arguments
  int[] | int[]   - returns intarray as a union of two arrays
  int[] & int[]   - returns intersection of arrays

Oleg Bartunov
This commit is contained in:
Bruce Momjian
2002-08-10 20:38:29 +00:00
parent c5354dff20
commit 181ca96e7a
5 changed files with 572 additions and 1 deletions

View File

@ -2217,3 +2217,303 @@ querytree(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER( res );
}
/*
** Additional array functions
*/
static int32 intarray_match_first(ArrayType *a, int32 elem);
static ArrayType *intarray_add_elem(ArrayType *a, int32 elem);
static ArrayType *intarray_concat_arrays(ArrayType *a, ArrayType *b);
static ArrayType *int_to_intset(int32 elem);
PG_FUNCTION_INFO_V1( intset );
PG_FUNCTION_INFO_V1( icount );
PG_FUNCTION_INFO_V1( sort );
PG_FUNCTION_INFO_V1( sort_asc );
PG_FUNCTION_INFO_V1( sort_desc );
PG_FUNCTION_INFO_V1( uniq );
PG_FUNCTION_INFO_V1( idx );
PG_FUNCTION_INFO_V1( subarray );
PG_FUNCTION_INFO_V1( intarray_push_elem );
PG_FUNCTION_INFO_V1( intarray_push_array );
PG_FUNCTION_INFO_V1( intarray_del_elem );
PG_FUNCTION_INFO_V1( intset_union_elem );
PG_FUNCTION_INFO_V1( intset_subtract );
Datum intset(PG_FUNCTION_ARGS);
Datum icount(PG_FUNCTION_ARGS);
Datum sort(PG_FUNCTION_ARGS);
Datum sort_asc(PG_FUNCTION_ARGS);
Datum sort_desc(PG_FUNCTION_ARGS);
Datum uniq(PG_FUNCTION_ARGS);
Datum idx(PG_FUNCTION_ARGS);
Datum subarray(PG_FUNCTION_ARGS);
Datum intarray_push_elem(PG_FUNCTION_ARGS);
Datum intarray_push_array(PG_FUNCTION_ARGS);
Datum intarray_del_elem(PG_FUNCTION_ARGS);
Datum intset_union_elem(PG_FUNCTION_ARGS);
Datum intset_subtract(PG_FUNCTION_ARGS);
static int32
intarray_match_first(ArrayType *a, int32 elem) {
int32 *aa, c, i;
c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
aa = ARRPTR(a);
for (i = 0; i < c; i++)
if (aa[i] == elem) return (i + 1);
return 0;
}
static ArrayType *
intarray_add_elem(ArrayType *a, int32 elem) {
ArrayType *result;
int32 *r;
int32 c = (ARRISVOID(a)) ? 0 : 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;
}
static ArrayType *
intarray_concat_arrays(ArrayType *a, ArrayType *b) {
ArrayType *result;
int32 ac = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
int32 bc = (ARRISVOID(b)) ? 0 : ARRNELEMS(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;
}
static ArrayType *
int_to_intset(int32 n) {
ArrayType *result;
int32 *aa;
result = new_intArrayType(1);
aa = ARRPTR(result);
aa[0] = n;
return result;
}
static int
compASC(const void *a, const void *b) {
if ( *(int4*)a == *(int4*)b ) return 0;
return ( *(int4*)a > *(int4*)b ) ? 1 : -1;
}
static int
compDESC(const void *a, const void *b) {
if ( *(int4*)a == *(int4*)b ) return 0;
return ( *(int4*)a < *(int4*)b ) ? 1 : -1;
}
#define QSORT(a, direction) \
if (ARRNELEMS(a) > 1) \
qsort((void*)ARRPTR(a), ARRNELEMS(a),sizeof(int4), \
(direction) ? compASC : compDESC )
#define UNIX_UNIQ(a) a = resize_intArrayType(a, unix_uniq(ARRPTR(a), ARRNELEMS(a)))
static int32
unix_uniq(int32 *array, int32 count) {
register int32 i, k = 0;
for (i = 1; i < count; i++)
if (array[k] != array[i]) {
k++;
if (i > k) array[k] = array[i];
}
return (k+1);
}
Datum
intset(PG_FUNCTION_ARGS) {
PG_RETURN_POINTER(int_to_intset(PG_GETARG_INT32(0)));
}
Datum
icount(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
int32 count = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
PG_FREE_IF_COPY(a, 0);
PG_RETURN_INT32(count);
}
Datum
sort(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
text *dirstr = ( fcinfo->nargs==2 ) ? PG_GETARG_TEXT_P(1) : NULL;
int32 dc = ( dirstr ) ? VARSIZE(dirstr)-VARHDRSZ : 0;
char *d = ( dirstr ) ? VARDATA(dirstr) : NULL;
int dir = -1;
if (ARRISVOID(a) || ARRNELEMS(a) < 2) PG_RETURN_POINTER(a);
if (dirstr==NULL || (dc == 3
&& (d[0] == 'A' || d[0] == 'a')
&& (d[1] == 'S' || d[1] == 's')
&& (d[2] == 'C' || d[2] == 'c')))
dir = 1;
else if (dc == 4
&& (d[0] == 'D' || d[0] == 'd')
&& (d[1] == 'E' || d[1] == 'e')
&& (d[2] == 'S' || d[2] == 's')
&& (d[3] == 'C' || d[3] == 'c'))
dir = 0;
if (dir == -1)
elog(ERROR, "Invalid second parameter in function sort. It must be 'ASC' or 'DESC'.");
QSORT(a, dir);
PG_RETURN_POINTER(a);
}
Datum
sort_asc(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
if (ARRISVOID(a)) PG_RETURN_POINTER(a);
QSORT(a, 1);
PG_RETURN_POINTER(a);
}
Datum
sort_desc(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
if (ARRISVOID(a)) PG_RETURN_POINTER(a);
QSORT(a, 0);
PG_RETURN_POINTER(a);
}
Datum
uniq(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
if (ARRISVOID(a) || ARRNELEMS(a) < 2) PG_RETURN_POINTER(a);
UNIX_UNIQ(a);
PG_RETURN_POINTER(a);
}
Datum
idx(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
int32 result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
if (result) result = intarray_match_first(a, PG_GETARG_INT32(1));
PG_FREE_IF_COPY(a, 0);
PG_RETURN_INT32(result);
}
Datum
subarray(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
ArrayType *result;
int32 start = ( PG_GETARG_INT32(1) > 0 ) ? PG_GETARG_INT32(1)-1 : PG_GETARG_INT32(1);
int32 len = ( fcinfo->nargs==3 ) ? PG_GETARG_INT32(2) : 0;
int32 end = 0;
int32 c;
if ( ARRISVOID(a) ) {
PG_FREE_IF_COPY(a, 0);
PG_RETURN_POINTER( new_intArrayType(0) );
}
c = ARRNELEMS(a);
if ( start < 0 )
start = c + start;
if ( len < 0 )
end = c + len;
else if ( len == 0 )
end = c;
else
end = start + len;
if ( end > c )
end = c;
if ( start < 0 )
start = 0;
if ( start >= end || end <= 0 ) {
PG_FREE_IF_COPY(a, 0);
PG_RETURN_POINTER( new_intArrayType(0) );
}
result = new_intArrayType(end-start);
if (end-start > 0)
memcpy(ARRPTR(result), ARRPTR(a) + start, (end-start) * sizeof(int32));
PG_FREE_IF_COPY(a, 0);
PG_RETURN_POINTER(result);
}
Datum
intarray_push_elem(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
ArrayType *result;
result = intarray_add_elem(a, PG_GETARG_INT32(1));
PG_FREE_IF_COPY(a, 0);
PG_RETURN_POINTER(result);
}
Datum
intarray_push_array(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
ArrayType *b = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));
ArrayType *result;
result = intarray_concat_arrays(a, b);
PG_FREE_IF_COPY(a, 0);
PG_FREE_IF_COPY(b, 1);
PG_RETURN_POINTER(result);
}
Datum
intarray_del_elem(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
int32 c = (ARRISVOID(a)) ? 0 : ARRNELEMS(a);
int32 *aa = ARRPTR(a);
int32 n = 0, i;
int32 elem = PG_GETARG_INT32(1);
for (i = 0; i < c; i++)
if (aa[i] != elem) {
if (i > n) aa[n++] = aa[i];
else n++;
}
if (c > 0) a = resize_intArrayType(a, n);
PG_RETURN_POINTER(a);
}
Datum
intset_union_elem(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));
ArrayType *result;
result = intarray_add_elem(a, PG_GETARG_INT32(1));
PG_FREE_IF_COPY(a, 0);
QSORT(result, 1);
UNIX_UNIQ(result);
PG_RETURN_POINTER(result);
}
Datum
intset_subtract(PG_FUNCTION_ARGS) {
ArrayType *a = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0)));
ArrayType *b = (ArrayType*)DatumGetPointer(PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(1)));
ArrayType *result;
int32 ca = ARRISVOID(a);
int32 cb = ARRISVOID(b);
int32 *aa, *bb, *r;
int32 n = 0, i = 0, k = 0;
QSORT(a, 1); UNIX_UNIQ(a); ca = ARRNELEMS(a);
QSORT(b, 1); UNIX_UNIQ(b); cb = ARRNELEMS(b);
result = new_intArrayType(ca);
aa = ARRPTR(a);
bb = ARRPTR(b);
r = ARRPTR(result);
while (i < ca) {
if (k == cb || aa[i] < bb[k]) r[n++] = aa[i++];
else if (aa[i] == bb[k]) { i++; k++; }
else k++;
}
result = resize_intArrayType(result, n);
pfree(a); pfree(b);
PG_RETURN_POINTER(result);
}