@ -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 ) ;
}