/*------------------------------------------------------------------------- * * btutils.c-- * Utility code for Postgres btree implementation. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $Header: /cvsroot/pgsql/src/backend/access/nbtree/nbtutils.c,v 1.8 1997/03/18 18:38:46 scrappy Exp $ * *------------------------------------------------------------------------- */ #include #include #include #include #include #include #include #ifndef HAVE_MEMMOVE # include #else # include #endif ScanKey _bt_mkscankey(Relation rel, IndexTuple itup) { ScanKey skey; TupleDesc itupdesc; int natts; int i; Datum arg; RegProcedure proc; bool null; natts = rel->rd_rel->relnatts; itupdesc = RelationGetTupleDescriptor(rel); skey = (ScanKey) palloc(natts * sizeof(ScanKeyData)); for (i = 0; i < natts; i++) { arg = index_getattr(itup, i + 1, itupdesc, &null); proc = index_getprocid(rel, i + 1, BTORDER_PROC); ScanKeyEntryInitialize(&skey[i], 0x0, (AttrNumber) (i + 1), proc, arg); } return (skey); } void _bt_freeskey(ScanKey skey) { pfree(skey); } void _bt_freestack(BTStack stack) { BTStack ostack; while (stack != (BTStack) NULL) { ostack = stack; stack = stack->bts_parent; pfree(ostack->bts_btitem); pfree(ostack); } } /* * _bt_orderkeys() -- Put keys in a sensible order for conjunctive quals. * * The order of the keys in the qual match the ordering imposed by * the index. This routine only needs to be called if there are * more than one qual clauses using this index. */ void _bt_orderkeys(Relation relation, BTScanOpaque so) { ScanKey xform; ScanKeyData *cur; StrategyMap map; int nbytes; long test; int i, j; int init[BTMaxStrategyNumber+1]; ScanKey key; uint16 numberOfKeys, new_numberOfKeys = 0; AttrNumber attno = 1; numberOfKeys = so->numberOfKeys; key = so->keyData; if ( numberOfKeys <= 1 ) return; /* get space for the modified array of keys */ nbytes = BTMaxStrategyNumber * sizeof(ScanKeyData); xform = (ScanKey) palloc(nbytes); cur = &key[0]; if ( cur->sk_attno != 1 ) elog (WARN, "_bt_orderkeys: key(s) for attribute 1 missed"); memset(xform, 0, nbytes); map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation), BTMaxStrategyNumber, attno); for (j = 0; j <= BTMaxStrategyNumber; j++) init[j] = 0; /* check each key passed in */ for (i = 0; ; ) { if ( i < numberOfKeys ) cur = &key[i]; if ( i == numberOfKeys || cur->sk_attno != attno ) { if ( cur->sk_attno != attno + 1 && i < numberOfKeys ) { elog (WARN, "_bt_orderkeys: key(s) for attribute %d missed", attno + 1); } /* * If = has been specified, no other key will be used. * In case of key < 2 && key == 1 and so on * we have to set qual_ok to 0 */ if (init[BTEqualStrategyNumber - 1]) { ScanKeyData *eq, *chk; eq = &xform[BTEqualStrategyNumber - 1]; for (j = BTMaxStrategyNumber; --j >= 0; ) { if ( j == (BTEqualStrategyNumber - 1) || init[j] == 0 ) continue; chk = &xform[j]; test = (long) fmgr(chk->sk_procedure, eq->sk_argument, chk->sk_argument); if (!test) so->qual_ok = 0; } init[BTLessStrategyNumber - 1] = 0; init[BTLessEqualStrategyNumber - 1] = 0; init[BTGreaterEqualStrategyNumber - 1] = 0; init[BTGreaterStrategyNumber - 1] = 0; } /* only one of <, <= */ if (init[BTLessStrategyNumber - 1] && init[BTLessEqualStrategyNumber - 1]) { ScanKeyData *lt, *le; lt = &xform[BTLessStrategyNumber - 1]; le = &xform[BTLessEqualStrategyNumber - 1]; /* * DO NOT use the cached function stuff here -- this is key * ordering, happens only when the user expresses a hokey * qualification, and gets executed only once, anyway. The * transform maps are hard-coded, and can't be initialized * in the correct way. */ test = (long) fmgr(le->sk_procedure, lt->sk_argument, le->sk_argument); if (test) init[BTLessEqualStrategyNumber - 1] = 0; else init[BTLessStrategyNumber - 1] = 0; } /* only one of >, >= */ if (init[BTGreaterStrategyNumber - 1] && init[BTGreaterEqualStrategyNumber - 1]) { ScanKeyData *gt, *ge; gt = &xform[BTGreaterStrategyNumber - 1]; ge = &xform[BTGreaterEqualStrategyNumber - 1]; /* see note above on function cache */ test = (long) fmgr(ge->sk_procedure, gt->sk_argument, ge->sk_argument); if (test) init[BTGreaterEqualStrategyNumber - 1] = 0; else init[BTGreaterStrategyNumber - 1] = 0; } /* okay, reorder and count */ for (j = BTMaxStrategyNumber; --j >= 0; ) if (init[j]) key[new_numberOfKeys++] = xform[j]; if ( attno == 1 ) so->numberOfFirstKeys = new_numberOfKeys; if ( i == numberOfKeys ) break; /* initialization for new attno */ attno = cur->sk_attno; memset(xform, 0, nbytes); map = IndexStrategyGetStrategyMap(RelationGetIndexStrategy(relation), BTMaxStrategyNumber, attno); /* haven't looked at any strategies yet */ for (j = 0; j <= BTMaxStrategyNumber; j++) init[j] = 0; } for (j = BTMaxStrategyNumber; --j >= 0; ) { if (cur->sk_procedure == map->entry[j].sk_procedure) break; } /* have we seen one of these before? */ if (init[j]) { /* yup, use the appropriate value */ test = (long) FMGR_PTR2(cur->sk_func, cur->sk_procedure, cur->sk_argument, xform[j].sk_argument); if (test) xform[j].sk_argument = cur->sk_argument; else if ( j == (BTEqualStrategyNumber - 1) ) so->qual_ok = 0; /* key == a && key == b, but a != b */ } else { /* nope, use this value */ memmove(&xform[j], cur, sizeof(*cur)); init[j] = 1; } i++; } so->numberOfKeys = new_numberOfKeys; pfree(xform); } bool _bt_checkqual(IndexScanDesc scan, IndexTuple itup) { BTScanOpaque so; so = (BTScanOpaque) scan->opaque; if (so->numberOfKeys > 0) return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation), so->numberOfKeys, so->keyData)); else return (true); } bool _bt_checkforkeys(IndexScanDesc scan, IndexTuple itup, Size keysz) { BTScanOpaque so; so = (BTScanOpaque) scan->opaque; if ( keysz > 0 && so->numberOfKeys >= keysz ) return (index_keytest(itup, RelationGetTupleDescriptor(scan->relation), keysz, so->keyData)); else return (true); } BTItem _bt_formitem(IndexTuple itup) { int nbytes_btitem; BTItem btitem; Size tuplen; extern Oid newoid(); /* disallow nulls in btree keys */ if (itup->t_info & INDEX_NULL_MASK) elog(WARN, "btree indices cannot include null keys"); /* make a copy of the index tuple with room for the sequence number */ tuplen = IndexTupleSize(itup); nbytes_btitem = tuplen + (sizeof(BTItemData) - sizeof(IndexTupleData)); btitem = (BTItem) palloc(nbytes_btitem); memmove((char *) &(btitem->bti_itup), (char *) itup, tuplen); btitem->bti_oid = newoid(); return (btitem); }