4 #include "access/genam.h"
5 #include "access/heapam.h"
6 #include "access/htup_details.h"
7 #include "access/nbtree.h"
8 #include "catalog/indexing.h"
9 #include "catalog/pg_am.h"
10 #include "catalog/pg_amproc.h"
11 #include "catalog/pg_cast.h"
12 #include "catalog/pg_opclass.h"
13 #include "catalog/pg_type.h"
14 #include "executor/spi.h"
15 #include "utils/catcache.h"
16 #include "utils/fmgroids.h"
17 #include "utils/lsyscache.h"
18 #include "utils/memutils.h"
19 #if (PG_VERSION_NUM < 120000)
20 #include "utils/tqual.h"
22 #include "utils/syscache.h"
23 #include "utils/typcache.h"
27 #if (PG_VERSION_NUM >= 90400)
30 #define SNAPSHOT SnapshotNow
33 #if PG_VERSION_NUM >= 130000
34 #define heap_open(r, l) table_open((r), (l))
35 #define heap_close(r, l) table_close((r), (l))
39 getDefaultOpclass(Oid amoid, Oid typid)
45 Oid opclassOid = InvalidOid;
47 heapRel = heap_open(OperatorClassRelationId, AccessShareLock);
50 Anum_pg_opclass_opcmethod,
51 BTEqualStrategyNumber, F_OIDEQ,
52 ObjectIdGetDatum(amoid));
54 scan = systable_beginscan(heapRel,
55 OpclassAmNameNspIndexId, true,
58 while (HeapTupleIsValid((tuple = systable_getnext(scan))))
60 Form_pg_opclass opclass = (Form_pg_opclass)GETSTRUCT(tuple);
62 if ( opclass->opcintype == typid && opclass->opcdefault )
64 if ( OidIsValid(opclassOid) )
65 elog(ERROR, "Ambiguous opclass for type %u (access method %u)", typid, amoid);
66 #if (PG_VERSION_NUM >= 120000)
67 opclassOid = opclass->oid;
69 opclassOid = HeapTupleGetOid(tuple);
74 systable_endscan(scan);
75 heap_close(heapRel, AccessShareLock);
81 getAMProc(Oid amoid, Oid typid)
83 Oid opclassOid = getDefaultOpclass(amoid, typid);
84 Oid procOid = InvalidOid;
91 if ( !OidIsValid(opclassOid) )
93 typid = getBaseType(typid);
94 opclassOid = getDefaultOpclass(amoid, typid);
97 if ( !OidIsValid(opclassOid) )
103 * Search binary-coercible type
105 #ifdef SearchSysCacheList1
106 catlist = SearchSysCacheList1(CASTSOURCETARGET,
107 ObjectIdGetDatum(typid));
109 catlist = SearchSysCacheList(CASTSOURCETARGET, 1,
110 ObjectIdGetDatum(typid),
114 for (i = 0; i < catlist->n_members; i++)
116 HeapTuple tuple = &catlist->members[i]->tuple;
117 Form_pg_cast castForm = (Form_pg_cast)GETSTRUCT(tuple);
119 if ( castForm->castfunc == InvalidOid && castForm->castcontext == COERCION_CODE_IMPLICIT )
121 typid = castForm->casttarget;
122 opclassOid = getDefaultOpclass(amoid, typid);
123 if( OidIsValid(opclassOid) )
128 ReleaseSysCacheList(catlist);
131 if ( !OidIsValid(opclassOid) )
134 opfamilyOid = get_opclass_family(opclassOid);
136 heapRel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
137 ScanKeyInit(&skey[0],
138 Anum_pg_amproc_amprocfamily,
139 BTEqualStrategyNumber, F_OIDEQ,
140 ObjectIdGetDatum(opfamilyOid));
141 ScanKeyInit(&skey[1],
142 Anum_pg_amproc_amproclefttype,
143 BTEqualStrategyNumber, F_OIDEQ,
144 ObjectIdGetDatum(typid));
145 ScanKeyInit(&skey[2],
146 Anum_pg_amproc_amprocrighttype,
147 BTEqualStrategyNumber, F_OIDEQ,
148 ObjectIdGetDatum(typid));
149 #if PG_VERSION_NUM >= 90200
150 ScanKeyInit(&skey[3],
151 Anum_pg_amproc_amprocnum,
152 BTEqualStrategyNumber, F_OIDEQ,
153 Int32GetDatum(BTORDER_PROC));
156 scan = systable_beginscan(heapRel, AccessMethodProcedureIndexId, true,
158 #if PG_VERSION_NUM >= 90200
164 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
166 Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(tuple);
172 if ( OidIsValid(procOid) )
173 elog(ERROR,"Ambiguous support function for type %u (opclass %u)", typid, opfamilyOid);
174 procOid = amprocform->amproc;
177 elog(ERROR,"Unsupported access method");
181 systable_endscan(scan);
182 heap_close(heapRel, AccessShareLock);
187 static ProcTypeInfo *cacheProcs = NULL;
188 static int nCacheProcs = 0;
190 #ifndef TupleDescAttr
191 #define TupleDescAttr(tupdesc, i) ((tupdesc)->attrs[(i)])
197 ProcTypeInfo info = malloc(sizeof(ProcTypeInfoData));
200 elog(ERROR, "Can't allocate %u memory", (uint32)sizeof(ProcTypeInfoData));
203 info->typtype = get_typtype(typid);
205 if (info->typtype == 'c')
209 MemoryContext oldcontext;
211 tupdesc = lookup_rowtype_tupdesc(typid, -1);
213 if (tupdesc->natts != 2)
214 elog(ERROR,"Composite type has wrong number of fields");
215 if (TupleDescAttr(tupdesc, 1)->atttypid != FLOAT4OID)
216 elog(ERROR,"Second field of composite type is not float4");
218 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
219 info->tupDesc = CreateTupleDescCopyConstr(tupdesc);
220 MemoryContextSwitchTo(oldcontext);
222 ReleaseTupleDesc(tupdesc);
224 info->cmpFuncOid = getAMProc(BTREE_AM_OID,
225 TupleDescAttr(info->tupDesc, 0)->atttypid);
226 info->hashFuncOid = getAMProc(HASH_AM_OID,
227 TupleDescAttr(info->tupDesc, 0)->atttypid);
231 info->tupDesc = NULL;
234 info->cmpFuncOid = getAMProc(BTREE_AM_OID, typid);
235 info->hashFuncOid = getAMProc(HASH_AM_OID, typid);
238 get_typlenbyvalalign(typid, &info->typlen, &info->typbyval, &info->typalign);
239 info->hashFuncInited = info->cmpFuncInited = false;
246 getFmgrInfoCmp(ProcTypeInfo info)
248 if ( info->cmpFuncInited == false )
250 if ( !OidIsValid(info->cmpFuncOid) )
251 elog(ERROR, "Could not find cmp function for type %u", info->typid);
253 fmgr_info_cxt( info->cmpFuncOid, &info->cmpFunc, TopMemoryContext );
254 info->cmpFuncInited = true;
259 getFmgrInfoHash(ProcTypeInfo info)
261 if ( info->hashFuncInited == false )
263 if ( !OidIsValid(info->hashFuncOid) )
264 elog(ERROR, "Could not find hash function for type %u", info->typid);
266 fmgr_info_cxt( info->hashFuncOid, &info->hashFunc, TopMemoryContext );
267 info->hashFuncInited = true;
272 cmpProcTypeInfo(const void *a, const void *b)
274 ProcTypeInfo av = *(ProcTypeInfo*)a;
275 ProcTypeInfo bv = *(ProcTypeInfo*)b;
277 Assert( av->typid != bv->typid );
279 return ( av->typid > bv->typid ) ? 1 : -1;
285 ProcTypeInfo info = NULL;
287 if ( nCacheProcs == 1 )
289 if ( cacheProcs[0]->typid == typid )
291 /*cacheProcs[0]->hashFuncInited = cacheProcs[0]->cmpFuncInited = false;*/
292 return cacheProcs[0];
295 else if ( nCacheProcs > 1 )
297 ProcTypeInfo *StopMiddle;
298 ProcTypeInfo *StopLow = cacheProcs,
299 *StopHigh = cacheProcs + nCacheProcs;
301 while (StopLow < StopHigh) {
302 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
305 if ( info->typid == typid )
307 /* info->hashFuncInited = info->cmpFuncInited = false; */
310 else if ( info->typid < typid )
311 StopLow = StopMiddle + 1;
313 StopHigh = StopMiddle;
319 info = fillProcs(typid);
320 if ( nCacheProcs == 0 )
322 cacheProcs = malloc(sizeof(ProcTypeInfo));
325 elog(ERROR, "Can't allocate %u memory", (uint32)sizeof(ProcTypeInfo));
329 cacheProcs[0] = info;
334 ProcTypeInfo *cacheProcsTmp = realloc(cacheProcs, (nCacheProcs+1) * sizeof(ProcTypeInfo));
337 elog(ERROR, "Can't allocate %u memory", (uint32)sizeof(ProcTypeInfo) * (nCacheProcs+1));
340 cacheProcs = cacheProcsTmp;
341 cacheProcs[ nCacheProcs ] = info;
343 qsort(cacheProcs, nCacheProcs, sizeof(ProcTypeInfo), cmpProcTypeInfo);
347 /* info->hashFuncInited = info->cmpFuncInited = false; */
353 * WARNING. Array2SimpleArray* doesn't copy Datum!
356 Array2SimpleArray(ProcTypeInfo info, ArrayType *a)
358 SimpleArray *s = palloc(sizeof(SimpleArray));
363 info = findProcs(ARR_ELEMTYPE(a));
369 deconstruct_array(a, info->typid,
370 info->typlen, info->typbyval, info->typalign,
371 &s->elems, NULL, &s->nelems);
377 deconstructCompositeType(ProcTypeInfo info, Datum in, double *weight)
379 HeapTupleHeader rec = DatumGetHeapTupleHeader(in);
384 /* Build a temporary HeapTuple control structure */
385 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
386 ItemPointerSetInvalid(&(tuple.t_self));
387 tuple.t_tableOid = InvalidOid;
390 heap_deform_tuple(&tuple, info->tupDesc, values, nulls);
391 if (nulls[0] || nulls[1])
392 elog(ERROR, "Both fields in composite type could not be NULL");
395 *weight = DatumGetFloat4(values[1]);
400 cmpArrayElem(const void *a, const void *b, void *arg)
402 ProcTypeInfo info = (ProcTypeInfo)arg;
406 return DatumGetInt32( FCall2( &info->cmpFunc,
407 deconstructCompositeType(info, *(Datum*)a, NULL),
408 deconstructCompositeType(info, *(Datum*)b, NULL) ) );
410 return DatumGetInt32( FCall2( &info->cmpFunc,
411 *(Datum*)a, *(Datum*)b ) );
415 Array2SimpleArrayS(ProcTypeInfo info, ArrayType *a)
417 SimpleArray *s = Array2SimpleArray(info, a);
421 getFmgrInfoCmp(s->info);
423 qsort_arg(s->elems, s->nelems, sizeof(Datum), cmpArrayElem, s->info);
429 typedef struct cmpArrayElemData {
436 cmpArrayElemArg(const void *a, const void *b, void *arg)
438 cmpArrayElemData *data = (cmpArrayElemData*)arg;
441 if (data->info->tupDesc)
442 res = DatumGetInt32( FCall2( &data->info->cmpFunc,
443 deconstructCompositeType(data->info, *(Datum*)a, NULL),
444 deconstructCompositeType(data->info, *(Datum*)b, NULL) ) );
446 res = DatumGetInt32( FCall2( &data->info->cmpFunc,
447 *(Datum*)a, *(Datum*)b ) );
450 data->hasDuplicate = true;
456 * Uniquefy array and calculate TF. Although
457 * result doesn't depend on normalization, we
458 * normalize TF by length array to have possiblity
459 * to limit estimation for index support.
461 * Cache signals of needing of TF caclulation
465 Array2SimpleArrayU(ProcTypeInfo info, ArrayType *a, void *cache)
467 SimpleArray *s = Array2SimpleArray(info, a);
468 StatElem *stat = NULL;
470 if ( s->nelems > 0 && cache )
472 s->df = palloc(sizeof(double) * s->nelems);
473 s->df[0] = 1.0; /* init */
478 cmpArrayElemData data;
481 getFmgrInfoCmp(s->info);
483 data.hasDuplicate = false;
485 qsort_arg(s->elems, s->nelems, sizeof(Datum), cmpArrayElemArg, &data);
487 if ( data.hasDuplicate )
495 data = tmp = dr = s->elems;
497 while (tmp - data < num)
499 cmp = (tmp == dr) ? 0 : cmpArrayElem(tmp, dr, s->info);
504 s->df[ dr - data ] = 1.0;
509 s->df[ dr - data ] += 1.0;
514 s->nelems = dr + 1 - s->elems;
518 int tfm = getTFMethod();
520 for(i=0;i<s->nelems;i++)
522 stat = fingArrayStat(cache, s->info->typid, s->elems[i], stat);
528 s->df[i] = (1.0 + log( s->df[i] ));
530 s->df[i] *= stat->idf;
533 s->df[i] = stat->idf;
536 elog(ERROR,"Unknown TF method: %d", tfm);
541 s->df[i] = 0.0; /* unknown word */
548 for(i=0;i<s->nelems;i++)
550 stat = fingArrayStat(cache, s->info->typid, s->elems[i], stat);
552 s->df[i] = stat->idf;
558 else if (s->nelems > 0 && cache)
560 stat = fingArrayStat(cache, s->info->typid, s->elems[0], stat);
562 s->df[0] = stat->idf;
571 numOfIntersect(SimpleArray *a, SimpleArray *b)
575 Datum *aptr = a->elems,
577 ProcTypeInfo info = a->info;
579 Assert( a->info->typid == b->info->typid );
581 getFmgrInfoCmp(info);
583 while( aptr - a->elems < a->nelems && bptr - b->elems < b->nelems )
585 cmp = cmpArrayElem(aptr, bptr, info);
602 TFIDFSml(SimpleArray *a, SimpleArray *b)
605 Datum *aptr = a->elems,
607 ProcTypeInfo info = a->info;
609 double suma = 0.0, sumb = 0.0;
611 Assert( a->info->typid == b->info->typid );
615 getFmgrInfoCmp(info);
617 while( aptr - a->elems < a->nelems && bptr - b->elems < b->nelems )
619 cmp = cmpArrayElem(aptr, bptr, info);
622 suma += a->df[ aptr - a->elems ] * a->df[ aptr - a->elems ];
627 sumb += b->df[ bptr - b->elems ] * b->df[ bptr - b->elems ];
632 res += a->df[ aptr - a->elems ] * b->df[ bptr - b->elems ];
633 suma += a->df[ aptr - a->elems ] * a->df[ aptr - a->elems ];
634 sumb += b->df[ bptr - b->elems ] * b->df[ bptr - b->elems ];
641 * Compute last elements
643 while( aptr - a->elems < a->nelems )
645 suma += a->df[ aptr - a->elems ] * a->df[ aptr - a->elems ];
649 while( bptr - b->elems < b->nelems )
651 sumb += b->df[ bptr - b->elems ] * b->df[ bptr - b->elems ];
655 if ( suma > 0.0 && sumb > 0.0 )
656 res = res / sqrt( suma * sumb );
664 PG_FUNCTION_INFO_V1(arraysml);
665 Datum arraysml(PG_FUNCTION_ARGS);
667 arraysml(PG_FUNCTION_ARGS)
670 SimpleArray *sa, *sb;
672 fcinfo->flinfo->fn_extra = SearchArrayCache(
673 fcinfo->flinfo->fn_extra,
674 fcinfo->flinfo->fn_mcxt,
675 PG_GETARG_DATUM(0), &a, &sa, NULL);
676 fcinfo->flinfo->fn_extra = SearchArrayCache(
677 fcinfo->flinfo->fn_extra,
678 fcinfo->flinfo->fn_mcxt,
679 PG_GETARG_DATUM(1), &b, &sb, NULL);
681 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
682 elog(ERROR,"Arguments array are not the same type!");
684 if (ARRISVOID(a) || ARRISVOID(b))
685 PG_RETURN_FLOAT4(0.0);
690 PG_RETURN_FLOAT4( TFIDFSml(sa, sb) );
697 power = ((double)(sa->nelems)) * ((double)(sb->nelems));
698 cnt = numOfIntersect(sa, sb);
700 PG_RETURN_FLOAT4( ((double)cnt) / sqrt( power ) );
705 float4 res = (float4)numOfIntersect(sa, sb);
707 PG_RETURN_FLOAT4(res);
711 elog(ERROR,"Unsupported formula type of similarity");
714 PG_RETURN_FLOAT4(0.0); /* keep compiler quiet */
717 PG_FUNCTION_INFO_V1(arraysmlw);
718 Datum arraysmlw(PG_FUNCTION_ARGS);
720 arraysmlw(PG_FUNCTION_ARGS)
723 SimpleArray *sa, *sb;
724 bool useIntersect = PG_GETARG_BOOL(2);
725 double numerator = 0.0;
726 double denominatorA = 0.0,
733 fcinfo->flinfo->fn_extra = SearchArrayCache(
734 fcinfo->flinfo->fn_extra,
735 fcinfo->flinfo->fn_mcxt,
736 PG_GETARG_DATUM(0), &a, &sa, NULL);
737 fcinfo->flinfo->fn_extra = SearchArrayCache(
738 fcinfo->flinfo->fn_extra,
739 fcinfo->flinfo->fn_mcxt,
740 PG_GETARG_DATUM(1), &b, &sb, NULL);
742 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
743 elog(ERROR,"Arguments array are not the same type!");
745 if (ARRISVOID(a) || ARRISVOID(b))
746 PG_RETURN_FLOAT4(0.0);
749 if (info->tupDesc == NULL)
750 elog(ERROR, "Only weigthed (composite) types should be used");
751 getFmgrInfoCmp(info);
753 while(ai < sa->nelems && bi < sb->nelems)
755 Datum ad = deconstructCompositeType(info, sa->elems[ai], &tmpA),
756 bd = deconstructCompositeType(info, sb->elems[bi], &tmpB);
758 cmp = DatumGetInt32(FCall2(&info->cmpFunc, ad, bd));
761 if (useIntersect == false)
762 denominatorA += tmpA * tmpA;
764 } else if ( cmp > 0 ) {
765 if (useIntersect == false)
766 denominatorB += tmpB * tmpB;
769 denominatorA += tmpA * tmpA;
770 denominatorB += tmpB * tmpB;
771 numerator += tmpA * tmpB;
777 if (useIntersect == false) {
778 while(ai < sa->nelems) {
779 deconstructCompositeType(info, sa->elems[ai], &tmpA);
780 denominatorA += tmpA * tmpA;
784 while(bi < sb->nelems) {
785 deconstructCompositeType(info, sb->elems[bi], &tmpB);
786 denominatorB += tmpB * tmpB;
791 if (numerator != 0.0) {
792 numerator = numerator / sqrt( denominatorA * denominatorB );
795 PG_RETURN_FLOAT4(numerator);
798 PG_FUNCTION_INFO_V1(arraysml_op);
799 Datum arraysml_op(PG_FUNCTION_ARGS);
801 arraysml_op(PG_FUNCTION_ARGS)
804 SimpleArray *sa, *sb;
807 fcinfo->flinfo->fn_extra = SearchArrayCache(
808 fcinfo->flinfo->fn_extra,
809 fcinfo->flinfo->fn_mcxt,
810 PG_GETARG_DATUM(0), &a, &sa, NULL);
811 fcinfo->flinfo->fn_extra = SearchArrayCache(
812 fcinfo->flinfo->fn_extra,
813 fcinfo->flinfo->fn_mcxt,
814 PG_GETARG_DATUM(1), &b, &sb, NULL);
816 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
817 elog(ERROR,"Arguments array are not the same type!");
819 if (ARRISVOID(a) || ARRISVOID(b))
820 PG_RETURN_BOOL(false);
825 power = TFIDFSml(sa, sb);
831 power = sqrt( ((double)(sa->nelems)) * ((double)(sb->nelems)) );
833 if ( ((double)Min(sa->nelems, sb->nelems)) / power < GetSmlarLimit() )
834 PG_RETURN_BOOL(false);
836 cnt = numOfIntersect(sa, sb);
837 power = ((double)cnt) / power;
841 power = (double)numOfIntersect(sa, sb);
844 elog(ERROR,"Unsupported formula type of similarity");
847 PG_RETURN_BOOL(power >= GetSmlarLimit());
851 static char cachedFormula[QBSIZE];
852 static int cachedLen = 0;
853 static void *cachedPlan = NULL;
855 PG_FUNCTION_INFO_V1(arraysml_func);
856 Datum arraysml_func(PG_FUNCTION_ARGS);
858 arraysml_func(PG_FUNCTION_ARGS)
861 SimpleArray *sa, *sb;
863 float4 result = -1.0;
864 Oid arg[] = {INT4OID, INT4OID, INT4OID};
869 text *formula = PG_GETARG_TEXT_P(2);
871 fcinfo->flinfo->fn_extra = SearchArrayCache(
872 fcinfo->flinfo->fn_extra,
873 fcinfo->flinfo->fn_mcxt,
874 PG_GETARG_DATUM(0), &a, &sa, NULL);
875 fcinfo->flinfo->fn_extra = SearchArrayCache(
876 fcinfo->flinfo->fn_extra,
877 fcinfo->flinfo->fn_mcxt,
878 PG_GETARG_DATUM(1), &b, &sb, NULL);
880 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
881 elog(ERROR,"Arguments array are not the same type!");
883 if (ARRISVOID(a) || ARRISVOID(b))
884 PG_RETURN_BOOL(false);
886 cnt = numOfIntersect(sa, sb);
888 if ( VARSIZE(formula) - VARHDRSZ > QBSIZE - 1024 )
889 elog(ERROR,"Formula is too long");
893 if ( cachedPlan == NULL || cachedLen != VARSIZE(formula) - VARHDRSZ ||
894 memcmp( cachedFormula, VARDATA(formula), VARSIZE(formula) - VARHDRSZ ) != 0 )
896 char *ptr, buf[QBSIZE];
898 *cachedFormula = '\0';
900 SPI_freeplan(cachedPlan);
904 ptr = stpcpy( buf, "SELECT (" );
905 memcpy( ptr, VARDATA(formula), VARSIZE(formula) - VARHDRSZ );
906 ptr += VARSIZE(formula) - VARHDRSZ;
907 ptr = stpcpy( ptr, ")::float4 FROM");
908 ptr = stpcpy( ptr, " (SELECT $1 ::float8 AS i, $2 ::float8 AS a, $3 ::float8 AS b) AS N;");
911 plan = SPI_prepare(buf, 3, arg);
913 elog(ERROR, "SPI_prepare() failed");
915 cachedPlan = SPI_saveplan(plan);
917 elog(ERROR, "SPI_saveplan() failed");
920 cachedLen = VARSIZE(formula) - VARHDRSZ;
921 memcpy( cachedFormula, VARDATA(formula), VARSIZE(formula) - VARHDRSZ );
927 pars[0] = Int32GetDatum( cnt );
928 pars[1] = Int32GetDatum( sa->nelems );
929 pars[2] = Int32GetDatum( sb->nelems );
931 stat = SPI_execute_plan(plan, pars, NULL, true, 3);
933 elog(ERROR, "SPI_execute_plan() returns %d", stat);
935 if ( SPI_processed > 0)
936 result = DatumGetFloat4(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
940 PG_RETURN_FLOAT4(result);
943 PG_FUNCTION_INFO_V1(array_unique);
944 Datum array_unique(PG_FUNCTION_ARGS);
946 array_unique(PG_FUNCTION_ARGS)
948 ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
952 sa = Array2SimpleArrayU(NULL, a, NULL);
954 res = construct_array( sa->elems,
963 PG_FREE_IF_COPY(a, 0);
965 PG_RETURN_ARRAYTYPE_P(res);
968 PG_FUNCTION_INFO_V1(inarray);
969 Datum inarray(PG_FUNCTION_ARGS);
971 inarray(PG_FUNCTION_ARGS)
975 Datum query = PG_GETARG_DATUM(1);
982 fcinfo->flinfo->fn_extra = SearchArrayCache(
983 fcinfo->flinfo->fn_extra,
984 fcinfo->flinfo->fn_mcxt,
985 PG_GETARG_DATUM(0), &a, &sa, NULL);
987 queryTypeOid = get_fn_expr_argtype(fcinfo->flinfo, 1);
989 if ( queryTypeOid == InvalidOid )
990 elog(ERROR,"inarray: could not determine actual argument type");
992 if ( queryTypeOid != sa->info->typid )
993 elog(ERROR,"inarray: Type of array's element and type of argument are not the same");
995 getFmgrInfoCmp(sa->info);
997 StopHigh = sa->elems + sa->nelems;
999 while (StopLow < StopHigh)
1001 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
1002 cmp = cmpArrayElem(StopMiddle, &query, sa->info);
1007 if ( PG_NARGS() >= 3 )
1008 PG_RETURN_DATUM(PG_GETARG_DATUM(2));
1009 PG_RETURN_FLOAT4(1.0);
1012 StopLow = StopMiddle + 1;
1014 StopHigh = StopMiddle;
1017 if ( PG_NARGS() >= 4 )
1018 PG_RETURN_DATUM(PG_GETARG_DATUM(3));
1019 PG_RETURN_FLOAT4(0.0);