00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "postgres.h"
00018
00019 #include "access/heapam.h"
00020 #include "access/itup.h"
00021 #include "access/tuptoaster.h"
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 IndexTuple
00034 index_form_tuple(TupleDesc tupleDescriptor,
00035 Datum *values,
00036 bool *isnull)
00037 {
00038 char *tp;
00039 IndexTuple tuple;
00040 Size size,
00041 data_size,
00042 hoff;
00043 int i;
00044 unsigned short infomask = 0;
00045 bool hasnull = false;
00046 uint16 tupmask = 0;
00047 int numberOfAttributes = tupleDescriptor->natts;
00048
00049 #ifdef TOAST_INDEX_HACK
00050 Datum untoasted_values[INDEX_MAX_KEYS];
00051 bool untoasted_free[INDEX_MAX_KEYS];
00052 #endif
00053
00054 if (numberOfAttributes > INDEX_MAX_KEYS)
00055 ereport(ERROR,
00056 (errcode(ERRCODE_TOO_MANY_COLUMNS),
00057 errmsg("number of index columns (%d) exceeds limit (%d)",
00058 numberOfAttributes, INDEX_MAX_KEYS)));
00059
00060 #ifdef TOAST_INDEX_HACK
00061 for (i = 0; i < numberOfAttributes; i++)
00062 {
00063 Form_pg_attribute att = tupleDescriptor->attrs[i];
00064
00065 untoasted_values[i] = values[i];
00066 untoasted_free[i] = false;
00067
00068
00069 if (isnull[i] || att->attlen != -1)
00070 continue;
00071
00072
00073
00074
00075
00076 if (VARATT_IS_EXTERNAL(DatumGetPointer(values[i])))
00077 {
00078 untoasted_values[i] =
00079 PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)
00080 DatumGetPointer(values[i])));
00081 untoasted_free[i] = true;
00082 }
00083
00084
00085
00086
00087
00088 if (!VARATT_IS_EXTENDED(DatumGetPointer(untoasted_values[i])) &&
00089 VARSIZE(DatumGetPointer(untoasted_values[i])) > TOAST_INDEX_TARGET &&
00090 (att->attstorage == 'x' || att->attstorage == 'm'))
00091 {
00092 Datum cvalue = toast_compress_datum(untoasted_values[i]);
00093
00094 if (DatumGetPointer(cvalue) != NULL)
00095 {
00096
00097 if (untoasted_free[i])
00098 pfree(DatumGetPointer(untoasted_values[i]));
00099 untoasted_values[i] = cvalue;
00100 untoasted_free[i] = true;
00101 }
00102 }
00103 }
00104 #endif
00105
00106 for (i = 0; i < numberOfAttributes; i++)
00107 {
00108 if (isnull[i])
00109 {
00110 hasnull = true;
00111 break;
00112 }
00113 }
00114
00115 if (hasnull)
00116 infomask |= INDEX_NULL_MASK;
00117
00118 hoff = IndexInfoFindDataOffset(infomask);
00119 #ifdef TOAST_INDEX_HACK
00120 data_size = heap_compute_data_size(tupleDescriptor,
00121 untoasted_values, isnull);
00122 #else
00123 data_size = heap_compute_data_size(tupleDescriptor,
00124 values, isnull);
00125 #endif
00126 size = hoff + data_size;
00127 size = MAXALIGN(size);
00128
00129 tp = (char *) palloc0(size);
00130 tuple = (IndexTuple) tp;
00131
00132 heap_fill_tuple(tupleDescriptor,
00133 #ifdef TOAST_INDEX_HACK
00134 untoasted_values,
00135 #else
00136 values,
00137 #endif
00138 isnull,
00139 (char *) tp + hoff,
00140 data_size,
00141 &tupmask,
00142 (hasnull ? (bits8 *) tp + sizeof(IndexTupleData) : NULL));
00143
00144 #ifdef TOAST_INDEX_HACK
00145 for (i = 0; i < numberOfAttributes; i++)
00146 {
00147 if (untoasted_free[i])
00148 pfree(DatumGetPointer(untoasted_values[i]));
00149 }
00150 #endif
00151
00152
00153
00154
00155
00156
00157
00158 if (tupmask & HEAP_HASVARWIDTH)
00159 infomask |= INDEX_VAR_MASK;
00160
00161
00162
00163
00164
00165 if ((size & INDEX_SIZE_MASK) != size)
00166 ereport(ERROR,
00167 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00168 errmsg("index row requires %lu bytes, maximum size is %lu",
00169 (unsigned long) size,
00170 (unsigned long) INDEX_SIZE_MASK)));
00171
00172 infomask |= size;
00173
00174
00175
00176
00177 tuple->t_info = infomask;
00178 return tuple;
00179 }
00180
00181
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 Datum
00201 nocache_index_getattr(IndexTuple tup,
00202 int attnum,
00203 TupleDesc tupleDesc)
00204 {
00205 Form_pg_attribute *att = tupleDesc->attrs;
00206 char *tp;
00207 bits8 *bp = NULL;
00208 bool slow = false;
00209 int data_off;
00210 int off;
00211
00212
00213
00214
00215
00216
00217
00218
00219
00220
00221 data_off = IndexInfoFindDataOffset(tup->t_info);
00222
00223 attnum--;
00224
00225 if (IndexTupleHasNulls(tup))
00226 {
00227
00228
00229
00230
00231
00232
00233
00234 bp = (bits8 *) ((char *) tup + sizeof(IndexTupleData));
00235
00236
00237
00238
00239 {
00240 int byte = attnum >> 3;
00241 int finalbit = attnum & 0x07;
00242
00243
00244 if ((~bp[byte]) & ((1 << finalbit) - 1))
00245 slow = true;
00246 else
00247 {
00248
00249 int i;
00250
00251 for (i = 0; i < byte; i++)
00252 {
00253 if (bp[i] != 0xFF)
00254 {
00255 slow = true;
00256 break;
00257 }
00258 }
00259 }
00260 }
00261 }
00262
00263 tp = (char *) tup + data_off;
00264
00265 if (!slow)
00266 {
00267
00268
00269
00270
00271 if (att[attnum]->attcacheoff >= 0)
00272 {
00273 return fetchatt(att[attnum],
00274 tp + att[attnum]->attcacheoff);
00275 }
00276
00277
00278
00279
00280
00281
00282 if (IndexTupleHasVarwidths(tup))
00283 {
00284 int j;
00285
00286 for (j = 0; j <= attnum; j++)
00287 {
00288 if (att[j]->attlen <= 0)
00289 {
00290 slow = true;
00291 break;
00292 }
00293 }
00294 }
00295 }
00296
00297 if (!slow)
00298 {
00299 int natts = tupleDesc->natts;
00300 int j = 1;
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311 att[0]->attcacheoff = 0;
00312
00313
00314 while (j < natts && att[j]->attcacheoff > 0)
00315 j++;
00316
00317 off = att[j - 1]->attcacheoff + att[j - 1]->attlen;
00318
00319 for (; j < natts; j++)
00320 {
00321 if (att[j]->attlen <= 0)
00322 break;
00323
00324 off = att_align_nominal(off, att[j]->attalign);
00325
00326 att[j]->attcacheoff = off;
00327
00328 off += att[j]->attlen;
00329 }
00330
00331 Assert(j > attnum);
00332
00333 off = att[attnum]->attcacheoff;
00334 }
00335 else
00336 {
00337 bool usecache = true;
00338 int i;
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350 off = 0;
00351 for (i = 0;; i++)
00352 {
00353 if (IndexTupleHasNulls(tup) && att_isnull(i, bp))
00354 {
00355 usecache = false;
00356 continue;
00357 }
00358
00359
00360 if (usecache && att[i]->attcacheoff >= 0)
00361 off = att[i]->attcacheoff;
00362 else if (att[i]->attlen == -1)
00363 {
00364
00365
00366
00367
00368
00369
00370 if (usecache &&
00371 off == att_align_nominal(off, att[i]->attalign))
00372 att[i]->attcacheoff = off;
00373 else
00374 {
00375 off = att_align_pointer(off, att[i]->attalign, -1,
00376 tp + off);
00377 usecache = false;
00378 }
00379 }
00380 else
00381 {
00382
00383 off = att_align_nominal(off, att[i]->attalign);
00384
00385 if (usecache)
00386 att[i]->attcacheoff = off;
00387 }
00388
00389 if (i == attnum)
00390 break;
00391
00392 off = att_addlength_pointer(off, att[i]->attlen, tp + off);
00393
00394 if (usecache && att[i]->attlen <= 0)
00395 usecache = false;
00396 }
00397 }
00398
00399 return fetchatt(att[attnum], tp + off);
00400 }
00401
00402
00403
00404
00405
00406
00407
00408 void
00409 index_deform_tuple(IndexTuple tup, TupleDesc tupleDescriptor,
00410 Datum *values, bool *isnull)
00411 {
00412 int i;
00413
00414
00415 Assert(tupleDescriptor->natts <= INDEX_MAX_KEYS);
00416
00417 for (i = 0; i < tupleDescriptor->natts; i++)
00418 {
00419 values[i] = index_getattr(tup, i + 1, tupleDescriptor, &isnull[i]);
00420 }
00421 }
00422
00423
00424
00425
00426 IndexTuple
00427 CopyIndexTuple(IndexTuple source)
00428 {
00429 IndexTuple result;
00430 Size size;
00431
00432 size = IndexTupleSize(source);
00433 result = (IndexTuple) palloc(size);
00434 memcpy(result, source, size);
00435 return result;
00436 }