*** ./contrib/intarray/_int_op.c.orig 2006-05-31 02:12:13.000000000 +0400 --- ./contrib/intarray/_int_op.c 2008-04-22 19:29:47.000000000 +0400 *************** *** 471,473 **** --- 471,579 ---- pfree(b); PG_RETURN_POINTER(result); } + + + /** + * Additional things. + */ + + /* Binary search. */ + PG_FUNCTION_INFO_V1(bidx); + Datum bidx(PG_FUNCTION_ARGS); + Datum bidx(PG_FUNCTION_ARGS) + { + ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); + int32 result; + + CHECKARRVALID(a); + result = (ARRISVOID(a)) ? 0 : ARRNELEMS(a); + if (result) { + int32 key = PG_GETARG_INT32(1); + int32 *array = ARRPTR(a); + int32 *ret = bsearch(&key, array, ARRNELEMS(a), sizeof(int32), compASC); + if (ret) { + result = 1 + (ret - array); + } else { + result = 0; + } + } + PG_FREE_IF_COPY(a, 0); + PG_RETURN_INT32(result); + } + + + /** + * Creates (r = null) or shrinks (r != null) 2d array of + * int4 chunks (usually pairs). + */ + static ArrayType * + prepareArrayType2d(ArrayType *r, int num1, int num2) + { + int nbytes = ARR_OVERHEAD_NONULLS(2) + sizeof(int32) * num1 * num2; + if (!r) { + r = (ArrayType *) palloc0(nbytes); + } else { + r = (ArrayType *) repalloc(r, nbytes); + } + SET_VARSIZE(r, nbytes); + ARR_NDIM(r) = 2; + r->dataoffset = 0; /* marker for no null bitmap */ + ARR_ELEMTYPE(r) = INT4OID; + ((int *) ARR_DIMS(r))[0] = num1; + ((int *) ARR_DIMS(r))[1] = num2; + ((int *) ARR_LBOUND(r))[0] = 1; + ((int *) ARR_LBOUND(r))[1] = 1; + return r; + } + + + /* + * Operation group + count + sort. + * Returns array of pairs { count1, item1, count2, item2, ... } for + * array of { item1, item1, item2, ... } + */ + PG_FUNCTION_INFO_V1(_int_group_count_sort); + Datum _int_group_count_sort(PG_FUNCTION_ARGS); + Datum _int_group_count_sort(PG_FUNCTION_ARGS) + { + ArrayType *a = (ArrayType *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0))); + int asc = PG_GETARG_BOOL(1); + ArrayType *result; + + CHECKARRVALID(a); + if (!ARRISVOID(a)) { + /* Non-empty array. */ + int nitems = ARRNELEMS(a); + int32 *items = ARRPTR(a); + int32 *groups; + int i, r; + + /* Create array of groups: { { count1, item1 }, { count2, item2 }, ... } */ + result = prepareArrayType2d(NULL, nitems, 2); + groups = ARRPTR(result); + for (i = 0, r = 0; i < nitems; i++) { + if (i >= 1 && items[i] == items[i - 1]) { + /* r is always >= 2; groups[r - 2] points to a prev counter. */ + groups[r - 2]++; + } else { + /* New unique item found. */ + groups[r] = 1; /* initial counter */ + groups[r + 1] = items[i]; /* value */ + r += 2; + } + } + + /* Sort pairs of elements in the new array by second pair member (count). */ + /* FIRST element of a pair is count, so we may use standard compASC & compDESC. */ + qsort(groups, r / 2, sizeof(int32) * 2, (asc? compASC : compDESC)); + + /* r / 2 holds the exact size of the new array, shrink to it to save memory */ + result = prepareArrayType2d(result, r / 2, 2); + } else { + /* Empty array. */ + result = new_intArrayType(0); + } + + PG_FREE_IF_COPY(a, 0); + PG_RETURN_POINTER(result); + } *** ./contrib/intarray/_int.sql.in.orig 2008-05-05 18:38:51.000000000 +0400 --- ./contrib/intarray/_int.sql.in 2008-05-05 18:39:10.000000000 +0400 *************** *** 488,490 **** --- 488,516 ---- FUNCTION 3 ginint4_queryextract (internal, internal, int2), FUNCTION 4 ginint4_consistent (internal, int2, internal), STORAGE int4; + + + -- + -- Additional things. + -- + + -- Binary search in sorted array (great speed). + CREATE FUNCTION bidx(_int4, int4) + RETURNS int4 + AS 'MODULE_PATHNAME' + LANGUAGE C RETURNS NULL ON NULL INPUT IMMUTABLE; + + -- Function to group + count + sort SORTED (!!!) array with repeated values. + -- + -- Input: sorted array like { 1, 1, 1, 6, 6, 7, 7, 7, 7 } + -- Output: 2d array like { { 4, 7 }, { 3, 1 }, { 2, 6 } } + -- + -- Function counts same values, and for each unique value + -- adds to resulting array a pair: the second element of a pair is + -- an unique number, the first element is repeat count. + -- Resulting array is sorted descending (secont argument = false) + -- or ascending (true). + CREATE OR REPLACE FUNCTION _int_group_count_sort (int4[], boolean) + RETURNS int4[] + AS 'MODULE_PATHNAME','_int_group_count_sort' + LANGUAGE C VOLATILE RETURNS NULL ON NULL INPUT SECURITY INVOKER; *** ./contrib/intarray/uninstall__int.sql.orig 2008-05-05 18:19:27.000000000 +0400 --- ./contrib/intarray/uninstall__int.sql 2008-05-05 18:19:40.000000000 +0400 *************** *** 123,125 **** --- 123,133 ---- DROP FUNCTION querytree(query_int); DROP TYPE query_int CASCADE; + + -- + -- Additional things. + -- + + DROP FUNCTION bidx(_int4, int4); + + DROP FUNCTION _int_group_count_sort (int4[], boolean);