00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "postgres.h"
00020
00021 #include "executor/executor.h"
00022 #include "miscadmin.h"
00023 #include "utils/lsyscache.h"
00024 #include "utils/memutils.h"
00025
00026
00027 static TupleHashTable CurTupleHashTable = NULL;
00028
00029 static uint32 TupleHashTableHash(const void *key, Size keysize);
00030 static int TupleHashTableMatch(const void *key1, const void *key2,
00031 Size keysize);
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 bool
00054 execTuplesMatch(TupleTableSlot *slot1,
00055 TupleTableSlot *slot2,
00056 int numCols,
00057 AttrNumber *matchColIdx,
00058 FmgrInfo *eqfunctions,
00059 MemoryContext evalContext)
00060 {
00061 MemoryContext oldContext;
00062 bool result;
00063 int i;
00064
00065
00066 MemoryContextReset(evalContext);
00067 oldContext = MemoryContextSwitchTo(evalContext);
00068
00069
00070
00071
00072
00073
00074
00075 result = true;
00076
00077 for (i = numCols; --i >= 0;)
00078 {
00079 AttrNumber att = matchColIdx[i];
00080 Datum attr1,
00081 attr2;
00082 bool isNull1,
00083 isNull2;
00084
00085 attr1 = slot_getattr(slot1, att, &isNull1);
00086
00087 attr2 = slot_getattr(slot2, att, &isNull2);
00088
00089 if (isNull1 != isNull2)
00090 {
00091 result = false;
00092 break;
00093 }
00094
00095 if (isNull1)
00096 continue;
00097
00098
00099
00100 if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
00101 attr1, attr2)))
00102 {
00103 result = false;
00104 break;
00105 }
00106 }
00107
00108 MemoryContextSwitchTo(oldContext);
00109
00110 return result;
00111 }
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123 bool
00124 execTuplesUnequal(TupleTableSlot *slot1,
00125 TupleTableSlot *slot2,
00126 int numCols,
00127 AttrNumber *matchColIdx,
00128 FmgrInfo *eqfunctions,
00129 MemoryContext evalContext)
00130 {
00131 MemoryContext oldContext;
00132 bool result;
00133 int i;
00134
00135
00136 MemoryContextReset(evalContext);
00137 oldContext = MemoryContextSwitchTo(evalContext);
00138
00139
00140
00141
00142
00143
00144
00145 result = false;
00146
00147 for (i = numCols; --i >= 0;)
00148 {
00149 AttrNumber att = matchColIdx[i];
00150 Datum attr1,
00151 attr2;
00152 bool isNull1,
00153 isNull2;
00154
00155 attr1 = slot_getattr(slot1, att, &isNull1);
00156
00157 if (isNull1)
00158 continue;
00159
00160 attr2 = slot_getattr(slot2, att, &isNull2);
00161
00162 if (isNull2)
00163 continue;
00164
00165
00166
00167 if (!DatumGetBool(FunctionCall2(&eqfunctions[i],
00168 attr1, attr2)))
00169 {
00170 result = true;
00171 break;
00172 }
00173 }
00174
00175 MemoryContextSwitchTo(oldContext);
00176
00177 return result;
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187
00188 FmgrInfo *
00189 execTuplesMatchPrepare(int numCols,
00190 Oid *eqOperators)
00191 {
00192 FmgrInfo *eqFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
00193 int i;
00194
00195 for (i = 0; i < numCols; i++)
00196 {
00197 Oid eq_opr = eqOperators[i];
00198 Oid eq_function;
00199
00200 eq_function = get_opcode(eq_opr);
00201 fmgr_info(eq_function, &eqFunctions[i]);
00202 }
00203
00204 return eqFunctions;
00205 }
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217 void
00218 execTuplesHashPrepare(int numCols,
00219 Oid *eqOperators,
00220 FmgrInfo **eqFunctions,
00221 FmgrInfo **hashFunctions)
00222 {
00223 int i;
00224
00225 *eqFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
00226 *hashFunctions = (FmgrInfo *) palloc(numCols * sizeof(FmgrInfo));
00227
00228 for (i = 0; i < numCols; i++)
00229 {
00230 Oid eq_opr = eqOperators[i];
00231 Oid eq_function;
00232 Oid left_hash_function;
00233 Oid right_hash_function;
00234
00235 eq_function = get_opcode(eq_opr);
00236 if (!get_op_hash_functions(eq_opr,
00237 &left_hash_function, &right_hash_function))
00238 elog(ERROR, "could not find hash function for hash operator %u",
00239 eq_opr);
00240
00241 Assert(left_hash_function == right_hash_function);
00242 fmgr_info(eq_function, &(*eqFunctions)[i]);
00243 fmgr_info(right_hash_function, &(*hashFunctions)[i]);
00244 }
00245 }
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 TupleHashTable
00275 BuildTupleHashTable(int numCols, AttrNumber *keyColIdx,
00276 FmgrInfo *eqfunctions,
00277 FmgrInfo *hashfunctions,
00278 long nbuckets, Size entrysize,
00279 MemoryContext tablecxt, MemoryContext tempcxt)
00280 {
00281 TupleHashTable hashtable;
00282 HASHCTL hash_ctl;
00283
00284 Assert(nbuckets > 0);
00285 Assert(entrysize >= sizeof(TupleHashEntryData));
00286
00287
00288 nbuckets = Min(nbuckets, (long) ((work_mem * 1024L) / entrysize));
00289
00290 hashtable = (TupleHashTable) MemoryContextAlloc(tablecxt,
00291 sizeof(TupleHashTableData));
00292
00293 hashtable->numCols = numCols;
00294 hashtable->keyColIdx = keyColIdx;
00295 hashtable->tab_hash_funcs = hashfunctions;
00296 hashtable->tab_eq_funcs = eqfunctions;
00297 hashtable->tablecxt = tablecxt;
00298 hashtable->tempcxt = tempcxt;
00299 hashtable->entrysize = entrysize;
00300 hashtable->tableslot = NULL;
00301 hashtable->inputslot = NULL;
00302 hashtable->in_hash_funcs = NULL;
00303 hashtable->cur_eq_funcs = NULL;
00304
00305 MemSet(&hash_ctl, 0, sizeof(hash_ctl));
00306 hash_ctl.keysize = sizeof(TupleHashEntryData);
00307 hash_ctl.entrysize = entrysize;
00308 hash_ctl.hash = TupleHashTableHash;
00309 hash_ctl.match = TupleHashTableMatch;
00310 hash_ctl.hcxt = tablecxt;
00311 hashtable->hashtab = hash_create("TupleHashTable", nbuckets,
00312 &hash_ctl,
00313 HASH_ELEM | HASH_FUNCTION | HASH_COMPARE | HASH_CONTEXT);
00314
00315 return hashtable;
00316 }
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330 TupleHashEntry
00331 LookupTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
00332 bool *isnew)
00333 {
00334 TupleHashEntry entry;
00335 MemoryContext oldContext;
00336 TupleHashTable saveCurHT;
00337 TupleHashEntryData dummy;
00338 bool found;
00339
00340
00341 if (hashtable->tableslot == NULL)
00342 {
00343 TupleDesc tupdesc;
00344
00345 oldContext = MemoryContextSwitchTo(hashtable->tablecxt);
00346
00347
00348
00349
00350
00351 tupdesc = CreateTupleDescCopy(slot->tts_tupleDescriptor);
00352 hashtable->tableslot = MakeSingleTupleTableSlot(tupdesc);
00353 MemoryContextSwitchTo(oldContext);
00354 }
00355
00356
00357 oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
00358
00359
00360
00361
00362
00363
00364
00365 hashtable->inputslot = slot;
00366 hashtable->in_hash_funcs = hashtable->tab_hash_funcs;
00367 hashtable->cur_eq_funcs = hashtable->tab_eq_funcs;
00368
00369 saveCurHT = CurTupleHashTable;
00370 CurTupleHashTable = hashtable;
00371
00372
00373 dummy.firstTuple = NULL;
00374 entry = (TupleHashEntry) hash_search(hashtable->hashtab,
00375 &dummy,
00376 isnew ? HASH_ENTER : HASH_FIND,
00377 &found);
00378
00379 if (isnew)
00380 {
00381 if (found)
00382 {
00383
00384 *isnew = false;
00385 }
00386 else
00387 {
00388
00389
00390
00391
00392
00393
00394
00395 MemSet(entry, 0, hashtable->entrysize);
00396
00397
00398 MemoryContextSwitchTo(hashtable->tablecxt);
00399 entry->firstTuple = ExecCopySlotMinimalTuple(slot);
00400
00401 *isnew = true;
00402 }
00403 }
00404
00405 CurTupleHashTable = saveCurHT;
00406
00407 MemoryContextSwitchTo(oldContext);
00408
00409 return entry;
00410 }
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421 TupleHashEntry
00422 FindTupleHashEntry(TupleHashTable hashtable, TupleTableSlot *slot,
00423 FmgrInfo *eqfunctions,
00424 FmgrInfo *hashfunctions)
00425 {
00426 TupleHashEntry entry;
00427 MemoryContext oldContext;
00428 TupleHashTable saveCurHT;
00429 TupleHashEntryData dummy;
00430
00431
00432 oldContext = MemoryContextSwitchTo(hashtable->tempcxt);
00433
00434
00435
00436
00437
00438
00439
00440 hashtable->inputslot = slot;
00441 hashtable->in_hash_funcs = hashfunctions;
00442 hashtable->cur_eq_funcs = eqfunctions;
00443
00444 saveCurHT = CurTupleHashTable;
00445 CurTupleHashTable = hashtable;
00446
00447
00448 dummy.firstTuple = NULL;
00449 entry = (TupleHashEntry) hash_search(hashtable->hashtab,
00450 &dummy,
00451 HASH_FIND,
00452 NULL);
00453
00454 CurTupleHashTable = saveCurHT;
00455
00456 MemoryContextSwitchTo(oldContext);
00457
00458 return entry;
00459 }
00460
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475
00476
00477 static uint32
00478 TupleHashTableHash(const void *key, Size keysize)
00479 {
00480 MinimalTuple tuple = ((const TupleHashEntryData *) key)->firstTuple;
00481 TupleTableSlot *slot;
00482 TupleHashTable hashtable = CurTupleHashTable;
00483 int numCols = hashtable->numCols;
00484 AttrNumber *keyColIdx = hashtable->keyColIdx;
00485 FmgrInfo *hashfunctions;
00486 uint32 hashkey = 0;
00487 int i;
00488
00489 if (tuple == NULL)
00490 {
00491
00492 slot = hashtable->inputslot;
00493 hashfunctions = hashtable->in_hash_funcs;
00494 }
00495 else
00496 {
00497
00498
00499 slot = hashtable->tableslot;
00500 ExecStoreMinimalTuple(tuple, slot, false);
00501 hashfunctions = hashtable->tab_hash_funcs;
00502 }
00503
00504 for (i = 0; i < numCols; i++)
00505 {
00506 AttrNumber att = keyColIdx[i];
00507 Datum attr;
00508 bool isNull;
00509
00510
00511 hashkey = (hashkey << 1) | ((hashkey & 0x80000000) ? 1 : 0);
00512
00513 attr = slot_getattr(slot, att, &isNull);
00514
00515 if (!isNull)
00516 {
00517 uint32 hkey;
00518
00519 hkey = DatumGetUInt32(FunctionCall1(&hashfunctions[i],
00520 attr));
00521 hashkey ^= hkey;
00522 }
00523 }
00524
00525 return hashkey;
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538
00539 static int
00540 TupleHashTableMatch(const void *key1, const void *key2, Size keysize)
00541 {
00542 MinimalTuple tuple1 = ((const TupleHashEntryData *) key1)->firstTuple;
00543
00544 #ifdef USE_ASSERT_CHECKING
00545 MinimalTuple tuple2 = ((const TupleHashEntryData *) key2)->firstTuple;
00546 #endif
00547 TupleTableSlot *slot1;
00548 TupleTableSlot *slot2;
00549 TupleHashTable hashtable = CurTupleHashTable;
00550
00551
00552
00553
00554
00555
00556
00557 Assert(tuple1 != NULL);
00558 slot1 = hashtable->tableslot;
00559 ExecStoreMinimalTuple(tuple1, slot1, false);
00560 Assert(tuple2 == NULL);
00561 slot2 = hashtable->inputslot;
00562
00563
00564 if (execTuplesMatch(slot2,
00565 slot1,
00566 hashtable->numCols,
00567 hashtable->keyColIdx,
00568 hashtable->cur_eq_funcs,
00569 hashtable->tempcxt))
00570 return 0;
00571 else
00572 return 1;
00573 }