00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "postgres.h"
00027
00028 #include "access/gist_private.h"
00029 #include "utils/rel.h"
00030
00031 typedef struct
00032 {
00033 OffsetNumber *entries;
00034 int len;
00035 Datum *attr;
00036 bool *isnull;
00037 bool *dontcare;
00038 } GistSplitUnion;
00039
00040
00041
00042
00043
00044
00045
00046 static void
00047 gistunionsubkeyvec(GISTSTATE *giststate, IndexTuple *itvec,
00048 GistSplitUnion *gsvp)
00049 {
00050 IndexTuple *cleanedItVec;
00051 int i,
00052 cleanedLen = 0;
00053
00054 cleanedItVec = (IndexTuple *) palloc(sizeof(IndexTuple) * gsvp->len);
00055
00056 for (i = 0; i < gsvp->len; i++)
00057 {
00058 if (gsvp->dontcare && gsvp->dontcare[gsvp->entries[i]])
00059 continue;
00060
00061 cleanedItVec[cleanedLen++] = itvec[gsvp->entries[i] - 1];
00062 }
00063
00064 gistMakeUnionItVec(giststate, cleanedItVec, cleanedLen,
00065 gsvp->attr, gsvp->isnull);
00066
00067 pfree(cleanedItVec);
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079 static void
00080 gistunionsubkey(GISTSTATE *giststate, IndexTuple *itvec, GistSplitVector *spl)
00081 {
00082 GistSplitUnion gsvp;
00083
00084 gsvp.dontcare = spl->spl_dontcare;
00085
00086 gsvp.entries = spl->splitVector.spl_left;
00087 gsvp.len = spl->splitVector.spl_nleft;
00088 gsvp.attr = spl->spl_lattr;
00089 gsvp.isnull = spl->spl_lisnull;
00090
00091 gistunionsubkeyvec(giststate, itvec, &gsvp);
00092
00093 gsvp.entries = spl->splitVector.spl_right;
00094 gsvp.len = spl->splitVector.spl_nright;
00095 gsvp.attr = spl->spl_rattr;
00096 gsvp.isnull = spl->spl_risnull;
00097
00098 gistunionsubkeyvec(giststate, itvec, &gsvp);
00099 }
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112 static int
00113 findDontCares(Relation r, GISTSTATE *giststate, GISTENTRY *valvec,
00114 GistSplitVector *spl, int attno)
00115 {
00116 int i;
00117 GISTENTRY entry;
00118 int NumDontCare = 0;
00119
00120
00121
00122
00123
00124
00125
00126
00127 gistentryinit(entry, spl->splitVector.spl_rdatum, r, NULL,
00128 (OffsetNumber) 0, FALSE);
00129 for (i = 0; i < spl->splitVector.spl_nleft; i++)
00130 {
00131 int j = spl->splitVector.spl_left[i];
00132 float penalty = gistpenalty(giststate, attno, &entry, false,
00133 &valvec[j], false);
00134
00135 if (penalty == 0.0)
00136 {
00137 spl->spl_dontcare[j] = true;
00138 NumDontCare++;
00139 }
00140 }
00141
00142
00143 gistentryinit(entry, spl->splitVector.spl_ldatum, r, NULL,
00144 (OffsetNumber) 0, FALSE);
00145 for (i = 0; i < spl->splitVector.spl_nright; i++)
00146 {
00147 int j = spl->splitVector.spl_right[i];
00148 float penalty = gistpenalty(giststate, attno, &entry, false,
00149 &valvec[j], false);
00150
00151 if (penalty == 0.0)
00152 {
00153 spl->spl_dontcare[j] = true;
00154 NumDontCare++;
00155 }
00156 }
00157
00158 return NumDontCare;
00159 }
00160
00161
00162
00163
00164
00165
00166 static void
00167 removeDontCares(OffsetNumber *a, int *len, const bool *dontcare)
00168 {
00169 int origlen,
00170 newlen,
00171 i;
00172 OffsetNumber *curwpos;
00173
00174 origlen = newlen = *len;
00175 curwpos = a;
00176 for (i = 0; i < origlen; i++)
00177 {
00178 OffsetNumber ai = a[i];
00179
00180 if (dontcare[ai] == FALSE)
00181 {
00182
00183 *curwpos = ai;
00184 curwpos++;
00185 }
00186 else
00187 newlen--;
00188 }
00189
00190 *len = newlen;
00191 }
00192
00193
00194
00195
00196
00197
00198
00199 static void
00200 placeOne(Relation r, GISTSTATE *giststate, GistSplitVector *v,
00201 IndexTuple itup, OffsetNumber off, int attno)
00202 {
00203 GISTENTRY identry[INDEX_MAX_KEYS];
00204 bool isnull[INDEX_MAX_KEYS];
00205 bool toLeft = true;
00206
00207 gistDeCompressAtt(giststate, r, itup, NULL, (OffsetNumber) 0,
00208 identry, isnull);
00209
00210 for (; attno < giststate->tupdesc->natts; attno++)
00211 {
00212 float lpenalty,
00213 rpenalty;
00214 GISTENTRY entry;
00215
00216 gistentryinit(entry, v->spl_lattr[attno], r, NULL, 0, FALSE);
00217 lpenalty = gistpenalty(giststate, attno, &entry, v->spl_lisnull[attno],
00218 identry + attno, isnull[attno]);
00219 gistentryinit(entry, v->spl_rattr[attno], r, NULL, 0, FALSE);
00220 rpenalty = gistpenalty(giststate, attno, &entry, v->spl_risnull[attno],
00221 identry + attno, isnull[attno]);
00222
00223 if (lpenalty != rpenalty)
00224 {
00225 if (lpenalty > rpenalty)
00226 toLeft = false;
00227 break;
00228 }
00229 }
00230
00231 if (toLeft)
00232 v->splitVector.spl_left[v->splitVector.spl_nleft++] = off;
00233 else
00234 v->splitVector.spl_right[v->splitVector.spl_nright++] = off;
00235 }
00236
00237 #define SWAPVAR( s, d, t ) \
00238 do { \
00239 (t) = (s); \
00240 (s) = (d); \
00241 (d) = (t); \
00242 } while(0)
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257 static void
00258 supportSecondarySplit(Relation r, GISTSTATE *giststate, int attno,
00259 GIST_SPLITVEC *sv, Datum oldL, Datum oldR)
00260 {
00261 bool leaveOnLeft = true,
00262 tmpBool;
00263 GISTENTRY entryL,
00264 entryR,
00265 entrySL,
00266 entrySR;
00267
00268 gistentryinit(entryL, oldL, r, NULL, 0, FALSE);
00269 gistentryinit(entryR, oldR, r, NULL, 0, FALSE);
00270 gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
00271 gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
00272
00273 if (sv->spl_ldatum_exists && sv->spl_rdatum_exists)
00274 {
00275 float penalty1,
00276 penalty2;
00277
00278 penalty1 = gistpenalty(giststate, attno, &entryL, false, &entrySL, false) +
00279 gistpenalty(giststate, attno, &entryR, false, &entrySR, false);
00280 penalty2 = gistpenalty(giststate, attno, &entryL, false, &entrySR, false) +
00281 gistpenalty(giststate, attno, &entryR, false, &entrySL, false);
00282
00283 if (penalty1 > penalty2)
00284 leaveOnLeft = false;
00285 }
00286 else
00287 {
00288 GISTENTRY *entry1 = (sv->spl_ldatum_exists) ? &entryL : &entryR;
00289 float penalty1,
00290 penalty2;
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302 penalty1 = gistpenalty(giststate, attno, entry1, false, &entrySL, false);
00303 penalty2 = gistpenalty(giststate, attno, entry1, false, &entrySR, false);
00304
00305 if (penalty1 < penalty2)
00306 leaveOnLeft = (sv->spl_ldatum_exists) ? true : false;
00307 else
00308 leaveOnLeft = (sv->spl_rdatum_exists) ? true : false;
00309 }
00310
00311 if (leaveOnLeft == false)
00312 {
00313
00314
00315
00316 OffsetNumber *off,
00317 noff;
00318 Datum datum;
00319
00320 SWAPVAR(sv->spl_left, sv->spl_right, off);
00321 SWAPVAR(sv->spl_nleft, sv->spl_nright, noff);
00322 SWAPVAR(sv->spl_ldatum, sv->spl_rdatum, datum);
00323 gistentryinit(entrySL, sv->spl_ldatum, r, NULL, 0, FALSE);
00324 gistentryinit(entrySR, sv->spl_rdatum, r, NULL, 0, FALSE);
00325 }
00326
00327 if (sv->spl_ldatum_exists)
00328 gistMakeUnionKey(giststate, attno, &entryL, false, &entrySL, false,
00329 &sv->spl_ldatum, &tmpBool);
00330
00331 if (sv->spl_rdatum_exists)
00332 gistMakeUnionKey(giststate, attno, &entryR, false, &entrySR, false,
00333 &sv->spl_rdatum, &tmpBool);
00334
00335 sv->spl_ldatum_exists = sv->spl_rdatum_exists = false;
00336 }
00337
00338
00339
00340
00341
00342
00343 static void
00344 genericPickSplit(GISTSTATE *giststate, GistEntryVector *entryvec, GIST_SPLITVEC *v, int attno)
00345 {
00346 OffsetNumber i,
00347 maxoff;
00348 int nbytes;
00349 GistEntryVector *evec;
00350
00351 maxoff = entryvec->n - 1;
00352
00353 nbytes = (maxoff + 2) * sizeof(OffsetNumber);
00354
00355 v->spl_left = (OffsetNumber *) palloc(nbytes);
00356 v->spl_right = (OffsetNumber *) palloc(nbytes);
00357 v->spl_nleft = v->spl_nright = 0;
00358
00359 for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
00360 {
00361 if (i <= (maxoff - FirstOffsetNumber + 1) / 2)
00362 {
00363 v->spl_left[v->spl_nleft] = i;
00364 v->spl_nleft++;
00365 }
00366 else
00367 {
00368 v->spl_right[v->spl_nright] = i;
00369 v->spl_nright++;
00370 }
00371 }
00372
00373
00374
00375
00376 evec = palloc(sizeof(GISTENTRY) * entryvec->n + GEVHDRSZ);
00377
00378 evec->n = v->spl_nleft;
00379 memcpy(evec->vector, entryvec->vector + FirstOffsetNumber,
00380 sizeof(GISTENTRY) * evec->n);
00381 v->spl_ldatum = FunctionCall2Coll(&giststate->unionFn[attno],
00382 giststate->supportCollation[attno],
00383 PointerGetDatum(evec),
00384 PointerGetDatum(&nbytes));
00385
00386 evec->n = v->spl_nright;
00387 memcpy(evec->vector, entryvec->vector + FirstOffsetNumber + v->spl_nleft,
00388 sizeof(GISTENTRY) * evec->n);
00389 v->spl_rdatum = FunctionCall2Coll(&giststate->unionFn[attno],
00390 giststate->supportCollation[attno],
00391 PointerGetDatum(evec),
00392 PointerGetDatum(&nbytes));
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414 static bool
00415 gistUserPicksplit(Relation r, GistEntryVector *entryvec, int attno, GistSplitVector *v,
00416 IndexTuple *itup, int len, GISTSTATE *giststate)
00417 {
00418 GIST_SPLITVEC *sv = &v->splitVector;
00419
00420
00421
00422
00423
00424 sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
00425 sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
00426 sv->spl_ldatum = v->spl_lattr[attno];
00427 sv->spl_rdatum = v->spl_rattr[attno];
00428
00429
00430
00431
00432
00433 FunctionCall2Coll(&giststate->picksplitFn[attno],
00434 giststate->supportCollation[attno],
00435 PointerGetDatum(entryvec),
00436 PointerGetDatum(sv));
00437
00438 if (sv->spl_nleft == 0 || sv->spl_nright == 0)
00439 {
00440
00441
00442
00443
00444 ereport(DEBUG1,
00445 (errcode(ERRCODE_INTERNAL_ERROR),
00446 errmsg("picksplit method for column %d of index \"%s\" failed",
00447 attno + 1, RelationGetRelationName(r)),
00448 errhint("The index is not optimal. To optimize it, contact a developer, or try to use the column as the second one in the CREATE INDEX command.")));
00449
00450
00451
00452
00453
00454 sv->spl_ldatum_exists = (v->spl_lisnull[attno]) ? false : true;
00455 sv->spl_rdatum_exists = (v->spl_risnull[attno]) ? false : true;
00456 sv->spl_ldatum = v->spl_lattr[attno];
00457 sv->spl_rdatum = v->spl_rattr[attno];
00458
00459
00460 genericPickSplit(giststate, entryvec, sv, attno);
00461 }
00462 else
00463 {
00464
00465 if (sv->spl_left[sv->spl_nleft - 1] == InvalidOffsetNumber)
00466 sv->spl_left[sv->spl_nleft - 1] = (OffsetNumber) (entryvec->n - 1);
00467 if (sv->spl_right[sv->spl_nright - 1] == InvalidOffsetNumber)
00468 sv->spl_right[sv->spl_nright - 1] = (OffsetNumber) (entryvec->n - 1);
00469 }
00470
00471
00472 if (sv->spl_ldatum_exists || sv->spl_rdatum_exists)
00473 supportSecondarySplit(r, giststate, attno, sv,
00474 v->spl_lattr[attno], v->spl_rattr[attno]);
00475
00476
00477 v->spl_lattr[attno] = sv->spl_ldatum;
00478 v->spl_rattr[attno] = sv->spl_rdatum;
00479 v->spl_lisnull[attno] = false;
00480 v->spl_risnull[attno] = false;
00481
00482
00483
00484
00485
00486 v->spl_dontcare = NULL;
00487
00488 if (attno + 1 < giststate->tupdesc->natts)
00489 {
00490 int NumDontCare;
00491
00492
00493
00494
00495
00496
00497 if (gistKeyIsEQ(giststate, attno, sv->spl_ldatum, sv->spl_rdatum))
00498 return true;
00499
00500
00501
00502
00503
00504 v->spl_dontcare = (bool *) palloc0(sizeof(bool) * (entryvec->n + 1));
00505
00506 NumDontCare = findDontCares(r, giststate, entryvec->vector, v, attno);
00507
00508 if (NumDontCare > 0)
00509 {
00510
00511
00512
00513 removeDontCares(sv->spl_left, &sv->spl_nleft, v->spl_dontcare);
00514 removeDontCares(sv->spl_right, &sv->spl_nright, v->spl_dontcare);
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 if (sv->spl_nleft == 0 || sv->spl_nright == 0)
00531 {
00532 v->spl_dontcare = NULL;
00533 return true;
00534 }
00535
00536
00537
00538
00539
00540
00541
00542
00543 gistunionsubkey(giststate, itup, v);
00544
00545 if (NumDontCare == 1)
00546 {
00547
00548
00549
00550
00551
00552
00553
00554 OffsetNumber toMove;
00555
00556
00557 for (toMove = FirstOffsetNumber; toMove < entryvec->n; toMove++)
00558 {
00559 if (v->spl_dontcare[toMove])
00560 break;
00561 }
00562 Assert(toMove < entryvec->n);
00563
00564
00565 placeOne(r, giststate, v, itup[toMove - 1], toMove, attno + 1);
00566
00567
00568
00569
00570
00571
00572 }
00573 else
00574 return true;
00575 }
00576 }
00577
00578 return false;
00579 }
00580
00581
00582
00583
00584 static void
00585 gistSplitHalf(GIST_SPLITVEC *v, int len)
00586 {
00587 int i;
00588
00589 v->spl_nright = v->spl_nleft = 0;
00590 v->spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
00591 v->spl_right = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
00592 for (i = 1; i <= len; i++)
00593 if (i < len / 2)
00594 v->spl_right[v->spl_nright++] = i;
00595 else
00596 v->spl_left[v->spl_nleft++] = i;
00597
00598
00599 }
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622 void
00623 gistSplitByKey(Relation r, Page page, IndexTuple *itup, int len,
00624 GISTSTATE *giststate, GistSplitVector *v, int attno)
00625 {
00626 GistEntryVector *entryvec;
00627 OffsetNumber *offNullTuples;
00628 int nOffNullTuples = 0;
00629 int i;
00630
00631
00632
00633 entryvec = palloc(GEVHDRSZ + (len + 1) * sizeof(GISTENTRY));
00634 entryvec->n = len + 1;
00635 offNullTuples = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
00636
00637 for (i = 1; i <= len; i++)
00638 {
00639 Datum datum;
00640 bool IsNull;
00641
00642 datum = index_getattr(itup[i - 1], attno + 1, giststate->tupdesc,
00643 &IsNull);
00644 gistdentryinit(giststate, attno, &(entryvec->vector[i]),
00645 datum, r, page, i,
00646 FALSE, IsNull);
00647 if (IsNull)
00648 offNullTuples[nOffNullTuples++] = i;
00649 }
00650
00651 if (nOffNullTuples == len)
00652 {
00653
00654
00655
00656
00657
00658 v->spl_risnull[attno] = v->spl_lisnull[attno] = TRUE;
00659
00660 if (attno + 1 < giststate->tupdesc->natts)
00661 gistSplitByKey(r, page, itup, len, giststate, v, attno + 1);
00662 else
00663 gistSplitHalf(&v->splitVector, len);
00664 }
00665 else if (nOffNullTuples > 0)
00666 {
00667 int j = 0;
00668
00669
00670
00671
00672
00673 v->splitVector.spl_right = offNullTuples;
00674 v->splitVector.spl_nright = nOffNullTuples;
00675 v->spl_risnull[attno] = TRUE;
00676
00677 v->splitVector.spl_left = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
00678 v->splitVector.spl_nleft = 0;
00679 for (i = 1; i <= len; i++)
00680 if (j < v->splitVector.spl_nright && offNullTuples[j] == i)
00681 j++;
00682 else
00683 v->splitVector.spl_left[v->splitVector.spl_nleft++] = i;
00684
00685
00686 if (attno == 0 && giststate->tupdesc->natts == 1)
00687 {
00688 v->spl_dontcare = NULL;
00689 gistunionsubkey(giststate, itup, v);
00690 }
00691 }
00692 else
00693 {
00694
00695
00696
00697 if (gistUserPicksplit(r, entryvec, attno, v, itup, len, giststate))
00698 {
00699
00700
00701
00702
00703 Assert(attno + 1 < giststate->tupdesc->natts);
00704
00705 if (v->spl_dontcare == NULL)
00706 {
00707
00708
00709
00710
00711 gistSplitByKey(r, page, itup, len, giststate, v, attno + 1);
00712 }
00713 else
00714 {
00715
00716
00717
00718
00719 IndexTuple *newitup = (IndexTuple *) palloc(len * sizeof(IndexTuple));
00720 OffsetNumber *map = (OffsetNumber *) palloc(len * sizeof(OffsetNumber));
00721 int newlen = 0;
00722 GIST_SPLITVEC backupSplit;
00723
00724 for (i = 0; i < len; i++)
00725 {
00726 if (v->spl_dontcare[i + 1])
00727 {
00728 newitup[newlen] = itup[i];
00729 map[newlen] = i + 1;
00730 newlen++;
00731 }
00732 }
00733
00734 Assert(newlen > 0);
00735
00736
00737
00738
00739
00740 backupSplit = v->splitVector;
00741 backupSplit.spl_left = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
00742 memcpy(backupSplit.spl_left, v->splitVector.spl_left, sizeof(OffsetNumber) * v->splitVector.spl_nleft);
00743 backupSplit.spl_right = (OffsetNumber *) palloc(sizeof(OffsetNumber) * len);
00744 memcpy(backupSplit.spl_right, v->splitVector.spl_right, sizeof(OffsetNumber) * v->splitVector.spl_nright);
00745
00746
00747 gistSplitByKey(r, page, newitup, newlen, giststate, v, attno + 1);
00748
00749
00750 for (i = 0; i < v->splitVector.spl_nleft; i++)
00751 backupSplit.spl_left[backupSplit.spl_nleft++] = map[v->splitVector.spl_left[i] - 1];
00752 for (i = 0; i < v->splitVector.spl_nright; i++)
00753 backupSplit.spl_right[backupSplit.spl_nright++] = map[v->splitVector.spl_right[i] - 1];
00754
00755 v->splitVector = backupSplit;
00756 }
00757 }
00758 }
00759
00760
00761
00762
00763
00764
00765
00766
00767
00768
00769
00770
00771
00772
00773
00774 if (attno == 0 && giststate->tupdesc->natts > 1)
00775 {
00776 v->spl_dontcare = NULL;
00777 gistunionsubkey(giststate, itup, v);
00778 }
00779 }