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 #include "utils/tqual.h"
20 #include "utils/syscache.h"
21 #include "utils/typcache.h"
25 #if (PG_VERSION_NUM >= 90400)
28 #define SNAPSHOT SnapshotNow
32 getDefaultOpclass(Oid amoid, Oid typid)
38 Oid opclassOid = InvalidOid;
40 heapRel = heap_open(OperatorClassRelationId, AccessShareLock);
43 Anum_pg_opclass_opcmethod,
44 BTEqualStrategyNumber, F_OIDEQ,
45 ObjectIdGetDatum(amoid));
47 scan = systable_beginscan(heapRel,
48 OpclassAmNameNspIndexId, true,
51 while (HeapTupleIsValid((tuple = systable_getnext(scan))))
53 Form_pg_opclass opclass = (Form_pg_opclass)GETSTRUCT(tuple);
55 if ( opclass->opcintype == typid && opclass->opcdefault )
57 if ( OidIsValid(opclassOid) )
58 elog(ERROR, "Ambiguous opclass for type %u (access method %u)", typid, amoid);
59 opclassOid = HeapTupleGetOid(tuple);
63 systable_endscan(scan);
64 heap_close(heapRel, AccessShareLock);
70 getAMProc(Oid amoid, Oid typid)
72 Oid opclassOid = getDefaultOpclass(amoid, typid);
73 Oid procOid = InvalidOid;
80 if ( !OidIsValid(opclassOid) )
82 typid = getBaseType(typid);
83 opclassOid = getDefaultOpclass(amoid, typid);
86 if ( !OidIsValid(opclassOid) )
92 * Search binary-coercible type
94 #ifdef SearchSysCacheList1
95 catlist = SearchSysCacheList1(CASTSOURCETARGET,
96 ObjectIdGetDatum(typid));
98 catlist = SearchSysCacheList(CASTSOURCETARGET, 1,
99 ObjectIdGetDatum(typid),
103 for (i = 0; i < catlist->n_members; i++)
105 HeapTuple tuple = &catlist->members[i]->tuple;
106 Form_pg_cast castForm = (Form_pg_cast)GETSTRUCT(tuple);
108 if ( castForm->castfunc == InvalidOid && castForm->castcontext == COERCION_CODE_IMPLICIT )
110 typid = castForm->casttarget;
111 opclassOid = getDefaultOpclass(amoid, typid);
112 if( OidIsValid(opclassOid) )
117 ReleaseSysCacheList(catlist);
120 if ( !OidIsValid(opclassOid) )
123 opfamilyOid = get_opclass_family(opclassOid);
125 heapRel = heap_open(AccessMethodProcedureRelationId, AccessShareLock);
126 ScanKeyInit(&skey[0],
127 Anum_pg_amproc_amprocfamily,
128 BTEqualStrategyNumber, F_OIDEQ,
129 ObjectIdGetDatum(opfamilyOid));
130 ScanKeyInit(&skey[1],
131 Anum_pg_amproc_amproclefttype,
132 BTEqualStrategyNumber, F_OIDEQ,
133 ObjectIdGetDatum(typid));
134 ScanKeyInit(&skey[2],
135 Anum_pg_amproc_amprocrighttype,
136 BTEqualStrategyNumber, F_OIDEQ,
137 ObjectIdGetDatum(typid));
138 #if PG_VERSION_NUM >= 90200
139 ScanKeyInit(&skey[3],
140 Anum_pg_amproc_amprocnum,
141 BTEqualStrategyNumber, F_OIDEQ,
142 Int32GetDatum(BTORDER_PROC));
145 scan = systable_beginscan(heapRel, AccessMethodProcedureIndexId, true,
147 #if PG_VERSION_NUM >= 90200
153 while (HeapTupleIsValid(tuple = systable_getnext(scan)))
155 Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(tuple);
161 if ( OidIsValid(procOid) )
162 elog(ERROR,"Ambiguous support function for type %u (opclass %u)", typid, opfamilyOid);
163 procOid = amprocform->amproc;
166 elog(ERROR,"Unsupported access method");
170 systable_endscan(scan);
171 heap_close(heapRel, AccessShareLock);
176 static ProcTypeInfo *cacheProcs = NULL;
177 static int nCacheProcs = 0;
179 #ifndef TupleDescAttr
180 #define TupleDescAttr(tupdesc, i) ((tupdesc)->attrs[(i)])
186 ProcTypeInfo info = malloc(sizeof(ProcTypeInfoData));
189 elog(ERROR, "Can't allocate %u memory", (uint32)sizeof(ProcTypeInfoData));
192 info->typtype = get_typtype(typid);
194 if (info->typtype == 'c')
198 MemoryContext oldcontext;
200 tupdesc = lookup_rowtype_tupdesc(typid, -1);
202 if (tupdesc->natts != 2)
203 elog(ERROR,"Composite type has wrong number of fields");
204 if (TupleDescAttr(tupdesc, 1)->atttypid != FLOAT4OID)
205 elog(ERROR,"Second field of composite type is not float4");
207 oldcontext = MemoryContextSwitchTo(TopMemoryContext);
208 info->tupDesc = CreateTupleDescCopyConstr(tupdesc);
209 MemoryContextSwitchTo(oldcontext);
211 ReleaseTupleDesc(tupdesc);
213 info->cmpFuncOid = getAMProc(BTREE_AM_OID,
214 TupleDescAttr(info->tupDesc, 0)->atttypid);
215 info->hashFuncOid = getAMProc(HASH_AM_OID,
216 TupleDescAttr(info->tupDesc, 0)->atttypid);
220 info->tupDesc = NULL;
223 info->cmpFuncOid = getAMProc(BTREE_AM_OID, typid);
224 info->hashFuncOid = getAMProc(HASH_AM_OID, typid);
227 get_typlenbyvalalign(typid, &info->typlen, &info->typbyval, &info->typalign);
228 info->hashFuncInited = info->cmpFuncInited = false;
235 getFmgrInfoCmp(ProcTypeInfo info)
237 if ( info->cmpFuncInited == false )
239 if ( !OidIsValid(info->cmpFuncOid) )
240 elog(ERROR, "Could not find cmp function for type %u", info->typid);
242 fmgr_info_cxt( info->cmpFuncOid, &info->cmpFunc, TopMemoryContext );
243 info->cmpFuncInited = true;
248 getFmgrInfoHash(ProcTypeInfo info)
250 if ( info->hashFuncInited == false )
252 if ( !OidIsValid(info->hashFuncOid) )
253 elog(ERROR, "Could not find hash function for type %u", info->typid);
255 fmgr_info_cxt( info->hashFuncOid, &info->hashFunc, TopMemoryContext );
256 info->hashFuncInited = true;
261 cmpProcTypeInfo(const void *a, const void *b)
263 ProcTypeInfo av = *(ProcTypeInfo*)a;
264 ProcTypeInfo bv = *(ProcTypeInfo*)b;
266 Assert( av->typid != bv->typid );
268 return ( av->typid > bv->typid ) ? 1 : -1;
274 ProcTypeInfo info = NULL;
276 if ( nCacheProcs == 1 )
278 if ( cacheProcs[0]->typid == typid )
280 /*cacheProcs[0]->hashFuncInited = cacheProcs[0]->cmpFuncInited = false;*/
281 return cacheProcs[0];
284 else if ( nCacheProcs > 1 )
286 ProcTypeInfo *StopMiddle;
287 ProcTypeInfo *StopLow = cacheProcs,
288 *StopHigh = cacheProcs + nCacheProcs;
290 while (StopLow < StopHigh) {
291 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
294 if ( info->typid == typid )
296 /* info->hashFuncInited = info->cmpFuncInited = false; */
299 else if ( info->typid < typid )
300 StopLow = StopMiddle + 1;
302 StopHigh = StopMiddle;
308 info = fillProcs(typid);
309 if ( nCacheProcs == 0 )
311 cacheProcs = malloc(sizeof(ProcTypeInfo));
314 elog(ERROR, "Can't allocate %u memory", (uint32)sizeof(ProcTypeInfo));
318 cacheProcs[0] = info;
323 ProcTypeInfo *cacheProcsTmp = realloc(cacheProcs, (nCacheProcs+1) * sizeof(ProcTypeInfo));
326 elog(ERROR, "Can't allocate %u memory", (uint32)sizeof(ProcTypeInfo) * (nCacheProcs+1));
329 cacheProcs = cacheProcsTmp;
330 cacheProcs[ nCacheProcs ] = info;
332 qsort(cacheProcs, nCacheProcs, sizeof(ProcTypeInfo), cmpProcTypeInfo);
336 /* info->hashFuncInited = info->cmpFuncInited = false; */
342 * WARNING. Array2SimpleArray* doesn't copy Datum!
345 Array2SimpleArray(ProcTypeInfo info, ArrayType *a)
347 SimpleArray *s = palloc(sizeof(SimpleArray));
352 info = findProcs(ARR_ELEMTYPE(a));
358 deconstruct_array(a, info->typid,
359 info->typlen, info->typbyval, info->typalign,
360 &s->elems, NULL, &s->nelems);
366 deconstructCompositeType(ProcTypeInfo info, Datum in, double *weight)
368 HeapTupleHeader rec = DatumGetHeapTupleHeader(in);
373 /* Build a temporary HeapTuple control structure */
374 tuple.t_len = HeapTupleHeaderGetDatumLength(rec);
375 ItemPointerSetInvalid(&(tuple.t_self));
376 tuple.t_tableOid = InvalidOid;
379 heap_deform_tuple(&tuple, info->tupDesc, values, nulls);
380 if (nulls[0] || nulls[1])
381 elog(ERROR, "Both fields in composite type could not be NULL");
384 *weight = DatumGetFloat4(values[1]);
389 cmpArrayElem(const void *a, const void *b, void *arg)
391 ProcTypeInfo info = (ProcTypeInfo)arg;
395 return DatumGetInt32( FCall2( &info->cmpFunc,
396 deconstructCompositeType(info, *(Datum*)a, NULL),
397 deconstructCompositeType(info, *(Datum*)b, NULL) ) );
399 return DatumGetInt32( FCall2( &info->cmpFunc,
400 *(Datum*)a, *(Datum*)b ) );
404 Array2SimpleArrayS(ProcTypeInfo info, ArrayType *a)
406 SimpleArray *s = Array2SimpleArray(info, a);
410 getFmgrInfoCmp(s->info);
412 qsort_arg(s->elems, s->nelems, sizeof(Datum), cmpArrayElem, s->info);
418 typedef struct cmpArrayElemData {
425 cmpArrayElemArg(const void *a, const void *b, void *arg)
427 cmpArrayElemData *data = (cmpArrayElemData*)arg;
430 if (data->info->tupDesc)
431 res = DatumGetInt32( FCall2( &data->info->cmpFunc,
432 deconstructCompositeType(data->info, *(Datum*)a, NULL),
433 deconstructCompositeType(data->info, *(Datum*)b, NULL) ) );
435 res = DatumGetInt32( FCall2( &data->info->cmpFunc,
436 *(Datum*)a, *(Datum*)b ) );
439 data->hasDuplicate = true;
445 * Uniquefy array and calculate TF. Although
446 * result doesn't depend on normalization, we
447 * normalize TF by length array to have possiblity
448 * to limit estimation for index support.
450 * Cache signals of needing of TF caclulation
454 Array2SimpleArrayU(ProcTypeInfo info, ArrayType *a, void *cache)
456 SimpleArray *s = Array2SimpleArray(info, a);
457 StatElem *stat = NULL;
459 if ( s->nelems > 0 && cache )
461 s->df = palloc(sizeof(double) * s->nelems);
462 s->df[0] = 1.0; /* init */
467 cmpArrayElemData data;
470 getFmgrInfoCmp(s->info);
472 data.hasDuplicate = false;
474 qsort_arg(s->elems, s->nelems, sizeof(Datum), cmpArrayElemArg, &data);
476 if ( data.hasDuplicate )
484 data = tmp = dr = s->elems;
486 while (tmp - data < num)
488 cmp = (tmp == dr) ? 0 : cmpArrayElem(tmp, dr, s->info);
493 s->df[ dr - data ] = 1.0;
498 s->df[ dr - data ] += 1.0;
503 s->nelems = dr + 1 - s->elems;
507 int tfm = getTFMethod();
509 for(i=0;i<s->nelems;i++)
511 stat = fingArrayStat(cache, s->info->typid, s->elems[i], stat);
517 s->df[i] = (1.0 + log( s->df[i] ));
519 s->df[i] *= stat->idf;
522 s->df[i] = stat->idf;
525 elog(ERROR,"Unknown TF method: %d", tfm);
530 s->df[i] = 0.0; /* unknown word */
537 for(i=0;i<s->nelems;i++)
539 stat = fingArrayStat(cache, s->info->typid, s->elems[i], stat);
541 s->df[i] = stat->idf;
547 else if (s->nelems > 0 && cache)
549 stat = fingArrayStat(cache, s->info->typid, s->elems[0], stat);
551 s->df[0] = stat->idf;
560 numOfIntersect(SimpleArray *a, SimpleArray *b)
564 Datum *aptr = a->elems,
566 ProcTypeInfo info = a->info;
568 Assert( a->info->typid == b->info->typid );
570 getFmgrInfoCmp(info);
572 while( aptr - a->elems < a->nelems && bptr - b->elems < b->nelems )
574 cmp = cmpArrayElem(aptr, bptr, info);
591 TFIDFSml(SimpleArray *a, SimpleArray *b)
594 Datum *aptr = a->elems,
596 ProcTypeInfo info = a->info;
598 double suma = 0.0, sumb = 0.0;
600 Assert( a->info->typid == b->info->typid );
604 getFmgrInfoCmp(info);
606 while( aptr - a->elems < a->nelems && bptr - b->elems < b->nelems )
608 cmp = cmpArrayElem(aptr, bptr, info);
611 suma += a->df[ aptr - a->elems ] * a->df[ aptr - a->elems ];
616 sumb += b->df[ bptr - b->elems ] * b->df[ bptr - b->elems ];
621 res += a->df[ aptr - a->elems ] * b->df[ bptr - b->elems ];
622 suma += a->df[ aptr - a->elems ] * a->df[ aptr - a->elems ];
623 sumb += b->df[ bptr - b->elems ] * b->df[ bptr - b->elems ];
630 * Compute last elements
632 while( aptr - a->elems < a->nelems )
634 suma += a->df[ aptr - a->elems ] * a->df[ aptr - a->elems ];
638 while( bptr - b->elems < b->nelems )
640 sumb += b->df[ bptr - b->elems ] * b->df[ bptr - b->elems ];
644 if ( suma > 0.0 && sumb > 0.0 )
645 res = res / sqrt( suma * sumb );
653 PG_FUNCTION_INFO_V1(arraysml);
654 Datum arraysml(PG_FUNCTION_ARGS);
656 arraysml(PG_FUNCTION_ARGS)
659 SimpleArray *sa, *sb;
661 fcinfo->flinfo->fn_extra = SearchArrayCache(
662 fcinfo->flinfo->fn_extra,
663 fcinfo->flinfo->fn_mcxt,
664 PG_GETARG_DATUM(0), &a, &sa, NULL);
665 fcinfo->flinfo->fn_extra = SearchArrayCache(
666 fcinfo->flinfo->fn_extra,
667 fcinfo->flinfo->fn_mcxt,
668 PG_GETARG_DATUM(1), &b, &sb, NULL);
670 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
671 elog(ERROR,"Arguments array are not the same type!");
673 if (ARRISVOID(a) || ARRISVOID(b))
674 PG_RETURN_FLOAT4(0.0);
679 PG_RETURN_FLOAT4( TFIDFSml(sa, sb) );
686 power = ((double)(sa->nelems)) * ((double)(sb->nelems));
687 cnt = numOfIntersect(sa, sb);
689 PG_RETURN_FLOAT4( ((double)cnt) / sqrt( power ) );
694 float4 res = (float4)numOfIntersect(sa, sb);
696 PG_RETURN_FLOAT4(res);
700 elog(ERROR,"Unsupported formula type of similarity");
703 PG_RETURN_FLOAT4(0.0); /* keep compiler quiet */
706 PG_FUNCTION_INFO_V1(arraysmlw);
707 Datum arraysmlw(PG_FUNCTION_ARGS);
709 arraysmlw(PG_FUNCTION_ARGS)
712 SimpleArray *sa, *sb;
713 bool useIntersect = PG_GETARG_BOOL(2);
714 double numerator = 0.0;
715 double denominatorA = 0.0,
722 fcinfo->flinfo->fn_extra = SearchArrayCache(
723 fcinfo->flinfo->fn_extra,
724 fcinfo->flinfo->fn_mcxt,
725 PG_GETARG_DATUM(0), &a, &sa, NULL);
726 fcinfo->flinfo->fn_extra = SearchArrayCache(
727 fcinfo->flinfo->fn_extra,
728 fcinfo->flinfo->fn_mcxt,
729 PG_GETARG_DATUM(1), &b, &sb, NULL);
731 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
732 elog(ERROR,"Arguments array are not the same type!");
734 if (ARRISVOID(a) || ARRISVOID(b))
735 PG_RETURN_FLOAT4(0.0);
738 if (info->tupDesc == NULL)
739 elog(ERROR, "Only weigthed (composite) types should be used");
740 getFmgrInfoCmp(info);
742 while(ai < sa->nelems && bi < sb->nelems)
744 Datum ad = deconstructCompositeType(info, sa->elems[ai], &tmpA),
745 bd = deconstructCompositeType(info, sb->elems[bi], &tmpB);
747 cmp = DatumGetInt32(FCall2(&info->cmpFunc, ad, bd));
750 if (useIntersect == false)
751 denominatorA += tmpA * tmpA;
753 } else if ( cmp > 0 ) {
754 if (useIntersect == false)
755 denominatorB += tmpB * tmpB;
758 denominatorA += tmpA * tmpA;
759 denominatorB += tmpB * tmpB;
760 numerator += tmpA * tmpB;
766 if (useIntersect == false) {
767 while(ai < sa->nelems) {
768 deconstructCompositeType(info, sa->elems[ai], &tmpA);
769 denominatorA += tmpA * tmpA;
773 while(bi < sb->nelems) {
774 deconstructCompositeType(info, sb->elems[bi], &tmpB);
775 denominatorB += tmpB * tmpB;
780 if (numerator != 0.0) {
781 numerator = numerator / sqrt( denominatorA * denominatorB );
784 PG_RETURN_FLOAT4(numerator);
787 PG_FUNCTION_INFO_V1(arraysml_op);
788 Datum arraysml_op(PG_FUNCTION_ARGS);
790 arraysml_op(PG_FUNCTION_ARGS)
793 SimpleArray *sa, *sb;
796 fcinfo->flinfo->fn_extra = SearchArrayCache(
797 fcinfo->flinfo->fn_extra,
798 fcinfo->flinfo->fn_mcxt,
799 PG_GETARG_DATUM(0), &a, &sa, NULL);
800 fcinfo->flinfo->fn_extra = SearchArrayCache(
801 fcinfo->flinfo->fn_extra,
802 fcinfo->flinfo->fn_mcxt,
803 PG_GETARG_DATUM(1), &b, &sb, NULL);
805 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
806 elog(ERROR,"Arguments array are not the same type!");
808 if (ARRISVOID(a) || ARRISVOID(b))
809 PG_RETURN_BOOL(false);
814 power = TFIDFSml(sa, sb);
820 power = sqrt( ((double)(sa->nelems)) * ((double)(sb->nelems)) );
822 if ( ((double)Min(sa->nelems, sb->nelems)) / power < GetSmlarLimit() )
823 PG_RETURN_BOOL(false);
825 cnt = numOfIntersect(sa, sb);
826 power = ((double)cnt) / power;
830 power = (double)numOfIntersect(sa, sb);
833 elog(ERROR,"Unsupported formula type of similarity");
836 PG_RETURN_BOOL(power >= GetSmlarLimit());
840 static char cachedFormula[QBSIZE];
841 static int cachedLen = 0;
842 static void *cachedPlan = NULL;
844 PG_FUNCTION_INFO_V1(arraysml_func);
845 Datum arraysml_func(PG_FUNCTION_ARGS);
847 arraysml_func(PG_FUNCTION_ARGS)
850 SimpleArray *sa, *sb;
852 float4 result = -1.0;
853 Oid arg[] = {INT4OID, INT4OID, INT4OID};
858 text *formula = PG_GETARG_TEXT_P(2);
860 fcinfo->flinfo->fn_extra = SearchArrayCache(
861 fcinfo->flinfo->fn_extra,
862 fcinfo->flinfo->fn_mcxt,
863 PG_GETARG_DATUM(0), &a, &sa, NULL);
864 fcinfo->flinfo->fn_extra = SearchArrayCache(
865 fcinfo->flinfo->fn_extra,
866 fcinfo->flinfo->fn_mcxt,
867 PG_GETARG_DATUM(1), &b, &sb, NULL);
869 if ( ARR_ELEMTYPE(a) != ARR_ELEMTYPE(b) )
870 elog(ERROR,"Arguments array are not the same type!");
872 if (ARRISVOID(a) || ARRISVOID(b))
873 PG_RETURN_BOOL(false);
875 cnt = numOfIntersect(sa, sb);
877 if ( VARSIZE(formula) - VARHDRSZ > QBSIZE - 1024 )
878 elog(ERROR,"Formula is too long");
882 if ( cachedPlan == NULL || cachedLen != VARSIZE(formula) - VARHDRSZ ||
883 memcmp( cachedFormula, VARDATA(formula), VARSIZE(formula) - VARHDRSZ ) != 0 )
885 char *ptr, buf[QBSIZE];
887 *cachedFormula = '\0';
889 SPI_freeplan(cachedPlan);
893 ptr = stpcpy( buf, "SELECT (" );
894 memcpy( ptr, VARDATA(formula), VARSIZE(formula) - VARHDRSZ );
895 ptr += VARSIZE(formula) - VARHDRSZ;
896 ptr = stpcpy( ptr, ")::float4 FROM");
897 ptr = stpcpy( ptr, " (SELECT $1 ::float8 AS i, $2 ::float8 AS a, $3 ::float8 AS b) AS N;");
900 plan = SPI_prepare(buf, 3, arg);
902 elog(ERROR, "SPI_prepare() failed");
904 cachedPlan = SPI_saveplan(plan);
906 elog(ERROR, "SPI_saveplan() failed");
909 cachedLen = VARSIZE(formula) - VARHDRSZ;
910 memcpy( cachedFormula, VARDATA(formula), VARSIZE(formula) - VARHDRSZ );
916 pars[0] = Int32GetDatum( cnt );
917 pars[1] = Int32GetDatum( sa->nelems );
918 pars[2] = Int32GetDatum( sb->nelems );
920 stat = SPI_execute_plan(plan, pars, NULL, true, 3);
922 elog(ERROR, "SPI_execute_plan() returns %d", stat);
924 if ( SPI_processed > 0)
925 result = DatumGetFloat4(SPI_getbinval(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1, &isnull));
929 PG_RETURN_FLOAT4(result);
932 PG_FUNCTION_INFO_V1(array_unique);
933 Datum array_unique(PG_FUNCTION_ARGS);
935 array_unique(PG_FUNCTION_ARGS)
937 ArrayType *a = PG_GETARG_ARRAYTYPE_P(0);
941 sa = Array2SimpleArrayU(NULL, a, NULL);
943 res = construct_array( sa->elems,
952 PG_FREE_IF_COPY(a, 0);
954 PG_RETURN_ARRAYTYPE_P(res);
957 PG_FUNCTION_INFO_V1(inarray);
958 Datum inarray(PG_FUNCTION_ARGS);
960 inarray(PG_FUNCTION_ARGS)
964 Datum query = PG_GETARG_DATUM(1);
971 fcinfo->flinfo->fn_extra = SearchArrayCache(
972 fcinfo->flinfo->fn_extra,
973 fcinfo->flinfo->fn_mcxt,
974 PG_GETARG_DATUM(0), &a, &sa, NULL);
976 queryTypeOid = get_fn_expr_argtype(fcinfo->flinfo, 1);
978 if ( queryTypeOid == InvalidOid )
979 elog(ERROR,"inarray: could not determine actual argument type");
981 if ( queryTypeOid != sa->info->typid )
982 elog(ERROR,"inarray: Type of array's element and type of argument are not the same");
984 getFmgrInfoCmp(sa->info);
986 StopHigh = sa->elems + sa->nelems;
988 while (StopLow < StopHigh)
990 StopMiddle = StopLow + ((StopHigh - StopLow) >> 1);
991 cmp = cmpArrayElem(StopMiddle, &query, sa->info);
996 if ( PG_NARGS() >= 3 )
997 PG_RETURN_DATUM(PG_GETARG_DATUM(2));
998 PG_RETURN_FLOAT4(1.0);
1001 StopLow = StopMiddle + 1;
1003 StopHigh = StopMiddle;
1006 if ( PG_NARGS() >= 4 )
1007 PG_RETURN_DATUM(PG_GETARG_DATUM(3));
1008 PG_RETURN_FLOAT4(0.0);