Standard pgindent run for 8.1.
This commit is contained in:
parent
790c01d280
commit
1dc3498251
|
@ -236,8 +236,8 @@ gbt_ts_penalty(PG_FUNCTION_ARGS)
|
||||||
newdbl[2];
|
newdbl[2];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
We are allways using "double" timestamps here.
|
* We are allways using "double" timestamps here. Precision should be good
|
||||||
Precision should be good enough.
|
* enough.
|
||||||
*/
|
*/
|
||||||
orgdbl[0] = ((double) origentry->lower);
|
orgdbl[0] = ((double) origentry->lower);
|
||||||
orgdbl[1] = ((double) origentry->upper);
|
orgdbl[1] = ((double) origentry->upper);
|
||||||
|
|
|
@ -120,7 +120,9 @@ gbt_var_node_cp_len(const GBT_VARKEY * node, const gbtree_vinfo * tinfo)
|
||||||
if (tinfo->eml > 1)
|
if (tinfo->eml > 1)
|
||||||
{
|
{
|
||||||
return (i - l + 1);
|
return (i - l + 1);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -154,7 +156,9 @@ gbt_bytea_pf_match(const bytea *pf, const bytea *query, const gbtree_vinfo * tin
|
||||||
if (tinfo->eml > 1)
|
if (tinfo->eml > 1)
|
||||||
{
|
{
|
||||||
out = (varstr_cmp(q, nlen, n, nlen) == 0);
|
out = (varstr_cmp(q, nlen, n, nlen) == 0);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
out = TRUE;
|
out = TRUE;
|
||||||
for (k = 0; k < nlen; k++)
|
for (k = 0; k < nlen; k++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -28,7 +28,8 @@ typedef struct
|
||||||
/* Attribs */
|
/* Attribs */
|
||||||
|
|
||||||
enum gbtree_type t; /* data type */
|
enum gbtree_type t; /* data type */
|
||||||
int32 eml; /* cached pg_database_encoding_max_length (0: undefined) */
|
int32 eml; /* cached pg_database_encoding_max_length (0:
|
||||||
|
* undefined) */
|
||||||
bool trnc; /* truncate (=compress) key */
|
bool trnc; /* truncate (=compress) key */
|
||||||
|
|
||||||
/* Methods */
|
/* Methods */
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
* darcy@druid.net
|
* darcy@druid.net
|
||||||
* http://www.druid.net/darcy/
|
* http://www.druid.net/darcy/
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/chkpass/chkpass.c,v 1.13 2005/01/29 22:35:01 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/chkpass/chkpass.c,v 1.14 2005/10/15 02:49:04 momjian Exp $
|
||||||
* best viewed with tabs set to 4
|
* best viewed with tabs set to 4
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -90,8 +90,8 @@ chkpass_in(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
mysalt[0] = salt_chars[random() & 0x3f];
|
mysalt[0] = salt_chars[random() & 0x3f];
|
||||||
mysalt[1] = salt_chars[random() & 0x3f];
|
mysalt[1] = salt_chars[random() & 0x3f];
|
||||||
mysalt[2] = 0; /* technically the terminator is not
|
mysalt[2] = 0; /* technically the terminator is not necessary
|
||||||
* necessary but I like to play safe */
|
* but I like to play safe */
|
||||||
strcpy(result->password, crypt(str, mysalt));
|
strcpy(result->password, crypt(str, mysalt));
|
||||||
PG_RETURN_POINTER(result);
|
PG_RETURN_POINTER(result);
|
||||||
}
|
}
|
||||||
|
|
|
@ -329,8 +329,7 @@ g_cube_picksplit(GistEntryVector *entryvec,
|
||||||
size_waste = size_union - size_inter;
|
size_waste = size_union - size_inter;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* are these a more promising split than what we've already
|
* are these a more promising split than what we've already seen?
|
||||||
* seen?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (size_waste > waste || firsttime)
|
if (size_waste > waste || firsttime)
|
||||||
|
@ -356,24 +355,24 @@ g_cube_picksplit(GistEntryVector *entryvec,
|
||||||
rt_cube_size(datum_r, &size_r);
|
rt_cube_size(datum_r, &size_r);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now split up the regions between the two seeds. An important
|
* Now split up the regions between the two seeds. An important property
|
||||||
* property of this split algorithm is that the split vector v has the
|
* of this split algorithm is that the split vector v has the indices of
|
||||||
* indices of items to be split in order in its left and right
|
* items to be split in order in its left and right vectors. We exploit
|
||||||
* vectors. We exploit this property by doing a merge in the code
|
* this property by doing a merge in the code that actually splits the
|
||||||
* that actually splits the page.
|
* page.
|
||||||
*
|
*
|
||||||
* For efficiency, we also place the new index tuple in this loop. This
|
* For efficiency, we also place the new index tuple in this loop. This is
|
||||||
* is handled at the very end, when we have placed all the existing
|
* handled at the very end, when we have placed all the existing tuples
|
||||||
* tuples and i == maxoff + 1.
|
* and i == maxoff + 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
maxoff = OffsetNumberNext(maxoff);
|
maxoff = OffsetNumberNext(maxoff);
|
||||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we've already decided where to place this item, just put it
|
* If we've already decided where to place this item, just put it on
|
||||||
* on the right list. Otherwise, we need to figure out which page
|
* the right list. Otherwise, we need to figure out which page needs
|
||||||
* needs the least enlargement in order to store the item.
|
* the least enlargement in order to store the item.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (i == seed_1)
|
if (i == seed_1)
|
||||||
|
@ -542,8 +541,8 @@ cube_union(NDBOX * a, NDBOX * b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* use the potentially smaller of the two boxes (b) to fill in the
|
* use the potentially smaller of the two boxes (b) to fill in the result,
|
||||||
* result, padding absent dimensions with zeroes
|
* padding absent dimensions with zeroes
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < b->dim; i++)
|
for (i = 0; i < b->dim; i++)
|
||||||
{
|
{
|
||||||
|
@ -624,8 +623,7 @@ cube_inter(NDBOX * a, NDBOX * b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is it OK to return a non-null intersection for non-overlapping
|
* Is it OK to return a non-null intersection for non-overlapping boxes?
|
||||||
* boxes?
|
|
||||||
*/
|
*/
|
||||||
return (result);
|
return (result);
|
||||||
}
|
}
|
||||||
|
@ -713,8 +711,8 @@ cube_cmp(NDBOX * a, NDBOX * b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if all common dimensions are equal, the cube with more
|
* if all common dimensions are equal, the cube with more dimensions
|
||||||
* dimensions wins
|
* wins
|
||||||
*/
|
*/
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -736,8 +734,8 @@ cube_cmp(NDBOX * a, NDBOX * b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if all common dimensions are equal, the cube with more
|
* if all common dimensions are equal, the cube with more dimensions
|
||||||
* dimensions wins
|
* wins
|
||||||
*/
|
*/
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -797,10 +795,9 @@ cube_contains(NDBOX * a, NDBOX * b)
|
||||||
if (a->dim < b->dim)
|
if (a->dim < b->dim)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* the further comparisons will make sense if the excess
|
* the further comparisons will make sense if the excess dimensions of
|
||||||
* dimensions of (b) were zeroes Since both UL and UR coordinates
|
* (b) were zeroes Since both UL and UR coordinates must be zero, we
|
||||||
* must be zero, we can check them all without worrying about
|
* can check them all without worrying about which is which.
|
||||||
* which is which.
|
|
||||||
*/
|
*/
|
||||||
for (i = a->dim; i < b->dim; i++)
|
for (i = a->dim; i < b->dim; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -88,10 +88,10 @@ dbf_open(char *file, int flags)
|
||||||
dbh->db_nfields = (dbh->db_hlen - sizeof(dbf_header)) / sizeof(dbf_field);
|
dbh->db_nfields = (dbh->db_hlen - sizeof(dbf_header)) / sizeof(dbf_field);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* dbh->db_hlen - sizeof(dbf_header) isn't the correct size, cos
|
* dbh->db_hlen - sizeof(dbf_header) isn't the correct size, cos dbh->hlen
|
||||||
* dbh->hlen is in fact a little more cos of the 0x0D (and possibly
|
* is in fact a little more cos of the 0x0D (and possibly another byte,
|
||||||
* another byte, 0x4E, I have seen this somewhere). Because of
|
* 0x4E, I have seen this somewhere). Because of rounding everything turns
|
||||||
* rounding everything turns out right :)
|
* out right :)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ((fields = (f_descr *) calloc(dbh->db_nfields, sizeof(f_descr)))
|
if ((fields = (f_descr *) calloc(dbh->db_nfields, sizeof(f_descr)))
|
||||||
|
@ -155,8 +155,7 @@ dbf_write_head(dbhead * dbh)
|
||||||
now = time((time_t *) NULL);
|
now = time((time_t *) NULL);
|
||||||
dbf_time = localtime(&now);
|
dbf_time = localtime(&now);
|
||||||
head.dbh_year = dbf_time->tm_year;
|
head.dbh_year = dbf_time->tm_year;
|
||||||
head.dbh_month = dbf_time->tm_mon + 1; /* Months since January +
|
head.dbh_month = dbf_time->tm_mon + 1; /* Months since January + 1 */
|
||||||
* 1 */
|
|
||||||
head.dbh_day = dbf_time->tm_mday;
|
head.dbh_day = dbf_time->tm_mday;
|
||||||
|
|
||||||
put_long(head.dbh_records, dbh->db_records);
|
put_long(head.dbh_records, dbh->db_records);
|
||||||
|
|
|
@ -64,8 +64,7 @@ typedef struct
|
||||||
u_char dbf_type; /* field-type */
|
u_char dbf_type; /* field-type */
|
||||||
u_char dbf_reserved[4]; /* some reserved stuff */
|
u_char dbf_reserved[4]; /* some reserved stuff */
|
||||||
u_char dbf_flen; /* field-length */
|
u_char dbf_flen; /* field-length */
|
||||||
u_char dbf_dec; /* number of decimal positions if type is
|
u_char dbf_dec; /* number of decimal positions if type is 'N' */
|
||||||
* 'N' */
|
|
||||||
u_char dbf_stub[14]; /* stuff we don't need */
|
u_char dbf_stub[14]; /* stuff we don't need */
|
||||||
} dbf_field;
|
} dbf_field;
|
||||||
|
|
||||||
|
@ -89,15 +88,14 @@ typedef struct
|
||||||
u_char db_year; /* last update as YYMMDD */
|
u_char db_year; /* last update as YYMMDD */
|
||||||
u_char db_month;
|
u_char db_month;
|
||||||
u_char db_day;
|
u_char db_day;
|
||||||
u_long db_hlen; /* length of the diskheader, for
|
u_long db_hlen; /* length of the diskheader, for calculating
|
||||||
* calculating the offsets */
|
* the offsets */
|
||||||
u_long db_records; /* number of records */
|
u_long db_records; /* number of records */
|
||||||
u_long db_currec; /* current record-number starting at 0 */
|
u_long db_currec; /* current record-number starting at 0 */
|
||||||
u_short db_rlen; /* length of the record */
|
u_short db_rlen; /* length of the record */
|
||||||
u_char db_nfields; /* number of fields */
|
u_char db_nfields; /* number of fields */
|
||||||
u_char *db_buff; /* record-buffer to save malloc()'s */
|
u_char *db_buff; /* record-buffer to save malloc()'s */
|
||||||
f_descr *db_fields; /* pointer to an array of field-
|
f_descr *db_fields; /* pointer to an array of field- descriptions */
|
||||||
* descriptions */
|
|
||||||
} dbhead;
|
} dbhead;
|
||||||
|
|
||||||
/* structure that contains everything a user wants from a field, including
|
/* structure that contains everything a user wants from a field, including
|
||||||
|
|
|
@ -359,9 +359,8 @@ do_inserts(PGconn *conn, char *table, dbhead * dbh)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* make sure we can build the COPY query, note that we don't need to
|
* make sure we can build the COPY query, note that we don't need to just
|
||||||
* just add this value, since the COPY query is a separate query (see
|
* add this value, since the COPY query is a separate query (see below)
|
||||||
* below)
|
|
||||||
*/
|
*/
|
||||||
if (h < 17 + strlen(table))
|
if (h < 17 + strlen(table))
|
||||||
h = 17 + strlen(table);
|
h = 17 + strlen(table);
|
||||||
|
@ -386,12 +385,10 @@ do_inserts(PGconn *conn, char *table, dbhead * dbh)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end == 0) /* "end" is a user option, if not
|
if (end == 0) /* "end" is a user option, if not specified, */
|
||||||
* specified, */
|
|
||||||
end = dbh->db_records; /* then all records are processed. */
|
end = dbh->db_records; /* then all records are processed. */
|
||||||
|
|
||||||
if (t_block == 0) /* user not specified transaction block
|
if (t_block == 0) /* user not specified transaction block size */
|
||||||
* size */
|
|
||||||
t_block = end - begin; /* then we set it to be the full data */
|
t_block = end - begin; /* then we set it to be the full data */
|
||||||
|
|
||||||
for (i = begin; i < end; i++)
|
for (i = begin; i < end; i++)
|
||||||
|
@ -426,9 +423,8 @@ do_inserts(PGconn *conn, char *table, dbhead * dbh)
|
||||||
j = 0; /* counter for fields in the output */
|
j = 0; /* counter for fields in the output */
|
||||||
for (h = 0; h < dbh->db_nfields; h++)
|
for (h = 0; h < dbh->db_nfields; h++)
|
||||||
{
|
{
|
||||||
if (!strlen(fields[h].db_name)) /* When the new fieldname
|
if (!strlen(fields[h].db_name)) /* When the new fieldname is
|
||||||
* is empty, the field is
|
* empty, the field is skipped */
|
||||||
* skipped */
|
|
||||||
continue;
|
continue;
|
||||||
else
|
else
|
||||||
j++;
|
j++;
|
||||||
|
@ -639,8 +635,8 @@ main(int argc, char **argv)
|
||||||
usage();
|
usage();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* FIXME: Ivan thinks this is bad: printf("unknown
|
* FIXME: Ivan thinks this is bad: printf("unknown argument:
|
||||||
* argument: %s\n", argv[0]);
|
* %s\n", argv[0]);
|
||||||
*/
|
*/
|
||||||
exit(1);
|
exit(1);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -62,8 +62,7 @@ typedef struct remoteConn
|
||||||
{
|
{
|
||||||
PGconn *conn; /* Hold the remote connection */
|
PGconn *conn; /* Hold the remote connection */
|
||||||
int autoXactCursors;/* Indicates the number of open cursors,
|
int autoXactCursors;/* Indicates the number of open cursors,
|
||||||
* non-zero means we opened the xact
|
* non-zero means we opened the xact ourselves */
|
||||||
* ourselves */
|
|
||||||
} remoteConn;
|
} remoteConn;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -514,8 +513,7 @@ dblink_fetch(PG_FUNCTION_ARGS)
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch to memory context appropriate for multiple function
|
* switch to memory context appropriate for multiple function calls
|
||||||
* calls
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
|
@ -664,8 +662,7 @@ dblink_record(PG_FUNCTION_ARGS)
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch to memory context appropriate for multiple function
|
* switch to memory context appropriate for multiple function calls
|
||||||
* calls
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
|
@ -730,8 +727,8 @@ dblink_record(PG_FUNCTION_ARGS)
|
||||||
TEXTOID, -1, 0);
|
TEXTOID, -1, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* and save a copy of the command status string to return as
|
* and save a copy of the command status string to return as our
|
||||||
* our result tuple
|
* result tuple
|
||||||
*/
|
*/
|
||||||
sql_cmd_status = PQcmdStatus(res);
|
sql_cmd_status = PQcmdStatus(res);
|
||||||
funcctx->max_calls = 1;
|
funcctx->max_calls = 1;
|
||||||
|
@ -975,8 +972,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch to memory context appropriate for multiple function
|
* switch to memory context appropriate for multiple function calls
|
||||||
* calls
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
|
@ -989,8 +985,7 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
|
||||||
GET_STR(PG_GETARG_TEXT_P(0)))));
|
GET_STR(PG_GETARG_TEXT_P(0)))));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* need a tuple descriptor representing one INT and one TEXT
|
* need a tuple descriptor representing one INT and one TEXT column
|
||||||
* column
|
|
||||||
*/
|
*/
|
||||||
tupdesc = CreateTemplateTupleDesc(2, false);
|
tupdesc = CreateTemplateTupleDesc(2, false);
|
||||||
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "position",
|
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "position",
|
||||||
|
@ -999,8 +994,8 @@ dblink_get_pkey(PG_FUNCTION_ARGS)
|
||||||
TEXTOID, -1, 0);
|
TEXTOID, -1, 0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate attribute metadata needed later to produce tuples from
|
* Generate attribute metadata needed later to produce tuples from raw
|
||||||
* raw C strings
|
* C strings
|
||||||
*/
|
*/
|
||||||
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||||
funcctx->attinmeta = attinmeta;
|
funcctx->attinmeta = attinmeta;
|
||||||
|
@ -1145,8 +1140,8 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||||
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Source array is made up of key values that will be used to locate
|
* Source array is made up of key values that will be used to locate the
|
||||||
* the tuple of interest from the local system.
|
* tuple of interest from the local system.
|
||||||
*/
|
*/
|
||||||
src_ndim = ARR_NDIM(src_pkattvals_arry);
|
src_ndim = ARR_NDIM(src_pkattvals_arry);
|
||||||
src_dim = ARR_DIMS(src_pkattvals_arry);
|
src_dim = ARR_DIMS(src_pkattvals_arry);
|
||||||
|
@ -1178,8 +1173,8 @@ dblink_build_sql_insert(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Target array is made up of key values that will be used to build
|
* Target array is made up of key values that will be used to build the
|
||||||
* the SQL string for use on the remote system.
|
* SQL string for use on the remote system.
|
||||||
*/
|
*/
|
||||||
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
||||||
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
||||||
|
@ -1291,8 +1286,8 @@ dblink_build_sql_delete(PG_FUNCTION_ARGS)
|
||||||
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Target array is made up of key values that will be used to build
|
* Target array is made up of key values that will be used to build the
|
||||||
* the SQL string for use on the remote system.
|
* SQL string for use on the remote system.
|
||||||
*/
|
*/
|
||||||
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
||||||
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
||||||
|
@ -1414,8 +1409,8 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||||
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
tgt_pkattvals_arry = PG_GETARG_ARRAYTYPE_P(4);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Source array is made up of key values that will be used to locate
|
* Source array is made up of key values that will be used to locate the
|
||||||
* the tuple of interest from the local system.
|
* tuple of interest from the local system.
|
||||||
*/
|
*/
|
||||||
src_ndim = ARR_NDIM(src_pkattvals_arry);
|
src_ndim = ARR_NDIM(src_pkattvals_arry);
|
||||||
src_dim = ARR_DIMS(src_pkattvals_arry);
|
src_dim = ARR_DIMS(src_pkattvals_arry);
|
||||||
|
@ -1447,8 +1442,8 @@ dblink_build_sql_update(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Target array is made up of key values that will be used to build
|
* Target array is made up of key values that will be used to build the
|
||||||
* the SQL string for use on the remote system.
|
* SQL string for use on the remote system.
|
||||||
*/
|
*/
|
||||||
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
tgt_ndim = ARR_NDIM(tgt_pkattvals_arry);
|
||||||
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
tgt_dim = ARR_DIMS(tgt_pkattvals_arry);
|
||||||
|
@ -1894,8 +1889,8 @@ get_tuple_of_interest(Oid relid, int2vector *pkattnums, int16 pknumatts, char **
|
||||||
elog(ERROR, "SPI connect failure - returned %d", ret);
|
elog(ERROR, "SPI connect failure - returned %d", ret);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build sql statement to look up tuple of interest Use src_pkattvals
|
* Build sql statement to look up tuple of interest Use src_pkattvals as
|
||||||
* as the criteria.
|
* the criteria.
|
||||||
*/
|
*/
|
||||||
appendStringInfo(str, "SELECT * FROM %s WHERE ", relname);
|
appendStringInfo(str, "SELECT * FROM %s WHERE ", relname);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
* pending.c
|
* pending.c
|
||||||
* $Id: pending.c,v 1.22 2005/10/02 23:50:05 tgl Exp $
|
* $Id: pending.c,v 1.23 2005/10/15 02:49:04 momjian Exp $
|
||||||
* $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.22 2005/10/02 23:50:05 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/dbmirror/pending.c,v 1.23 2005/10/15 02:49:04 momjian Exp $
|
||||||
*
|
*
|
||||||
* This file contains a trigger for Postgresql-7.x to record changes to tables
|
* This file contains a trigger for Postgresql-7.x to record changes to tables
|
||||||
* to a pending table for mirroring.
|
* to a pending table for mirroring.
|
||||||
|
|
|
@ -367,9 +367,8 @@ breakup(char *string, char *substring)
|
||||||
while (cur_pos > string) /* don't read before start of 'string' */
|
while (cur_pos > string) /* don't read before start of 'string' */
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* skip pieces at the end of a string that are not alfa-numeric
|
* skip pieces at the end of a string that are not alfa-numeric (ie.
|
||||||
* (ie. 'string$%^&', last_start first points to '&', and after
|
* 'string$%^&', last_start first points to '&', and after this to 'g'
|
||||||
* this to 'g'
|
|
||||||
*/
|
*/
|
||||||
if (!isalnum((unsigned char) *last_start))
|
if (!isalnum((unsigned char) *last_start))
|
||||||
{
|
{
|
||||||
|
@ -379,8 +378,7 @@ breakup(char *string, char *substring)
|
||||||
cur_pos = last_start;
|
cur_pos = last_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
cur_pos--; /* substrings are at minimum 2 characters
|
cur_pos--; /* substrings are at minimum 2 characters long */
|
||||||
* long */
|
|
||||||
|
|
||||||
if (isalnum((unsigned char) *cur_pos))
|
if (isalnum((unsigned char) *cur_pos))
|
||||||
{
|
{
|
||||||
|
|
|
@ -48,8 +48,8 @@
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* $Revision: 1.5 $
|
* $Revision: 1.6 $
|
||||||
* $Id: dmetaphone.c,v 1.5 2005/09/30 22:38:44 momjian Exp $
|
* $Id: dmetaphone.c,v 1.6 2005/10/15 02:49:05 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -154,10 +154,10 @@ dmetaphone(PG_FUNCTION_ARGS)
|
||||||
alen = VARSIZE(arg) - VARHDRSZ;
|
alen = VARSIZE(arg) - VARHDRSZ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Postgres' string values might not have trailing nuls. The VARSIZE
|
* Postgres' string values might not have trailing nuls. The VARSIZE will
|
||||||
* will not include the nul in any case so we copy things out and add
|
* not include the nul in any case so we copy things out and add a
|
||||||
* a trailing nul. When we copy back we ignore the nul (and we don't
|
* trailing nul. When we copy back we ignore the nul (and we don't make
|
||||||
* make space for it).
|
* space for it).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
aptr = palloc(alen + 1);
|
aptr = palloc(alen + 1);
|
||||||
|
@ -236,7 +236,6 @@ dmetaphone_alt(PG_FUNCTION_ARGS)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define META_FREE(x) /* pfree((x)) */
|
#define META_FREE(x) /* pfree((x)) */
|
||||||
|
|
||||||
#else /* not defined DMETAPHONE_MAIN */
|
#else /* not defined DMETAPHONE_MAIN */
|
||||||
|
|
||||||
/* use the standard malloc library when not running in PostgreSQL */
|
/* use the standard malloc library when not running in PostgreSQL */
|
||||||
|
@ -787,8 +786,8 @@ DoubleMetaphone(char *str, char **codes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parker's rule (with some further refinements) -
|
* Parker's rule (with some further refinements) - e.g.,
|
||||||
* e.g., 'hugh'
|
* 'hugh'
|
||||||
*/
|
*/
|
||||||
if (
|
if (
|
||||||
((current > 1)
|
((current > 1)
|
||||||
|
@ -1187,8 +1186,8 @@ DoubleMetaphone(char *str, char **codes)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* german & anglicisations, e.g. 'smith' match 'schmidt',
|
* german & anglicisations, e.g. 'smith' match 'schmidt',
|
||||||
* 'snider' match 'schneider' also, -sz- in slavic
|
* 'snider' match 'schneider' also, -sz- in slavic language
|
||||||
* language although in hungarian it is pronounced 's'
|
* although in hungarian it is pronounced 's'
|
||||||
*/
|
*/
|
||||||
if (((current == 0)
|
if (((current == 0)
|
||||||
&& StringAt(original, (current + 1), 1,
|
&& StringAt(original, (current + 1), 1,
|
||||||
|
@ -1442,8 +1441,8 @@ DoubleMetaphone(char *str, char **codes)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* printf("PRIMARY: %s\n", primary->str); printf("SECONDARY:
|
* printf("PRIMARY: %s\n", primary->str); printf("SECONDARY: %s\n",
|
||||||
* %s\n", secondary->str);
|
* secondary->str);
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,10 +65,10 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fetch the arguments. str_s is referred to as the "source" cols =
|
* Fetch the arguments. str_s is referred to as the "source" cols = length
|
||||||
* length of source + 1 to allow for the initialization column str_t
|
* of source + 1 to allow for the initialization column str_t is referred
|
||||||
* is referred to as the "target", rows = length of target + 1 rows =
|
* to as the "target", rows = length of target + 1 rows = length of target
|
||||||
* length of target + 1 to allow for the initialization row
|
* + 1 to allow for the initialization row
|
||||||
*/
|
*/
|
||||||
str_s = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
|
str_s = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(0))));
|
||||||
str_t = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(1))));
|
str_t = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(PG_GETARG_TEXT_P(1))));
|
||||||
|
@ -78,10 +78,9 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Restrict the length of the strings being compared to something
|
* Restrict the length of the strings being compared to something
|
||||||
* reasonable because we will have to perform rows * cols
|
* reasonable because we will have to perform rows * cols calculations. If
|
||||||
* calculations. If longer strings need to be compared, increase
|
* longer strings need to be compared, increase MAX_LEVENSHTEIN_STRLEN to
|
||||||
* MAX_LEVENSHTEIN_STRLEN to suit (but within your tolerance for speed
|
* suit (but within your tolerance for speed and memory usage).
|
||||||
* and memory usage).
|
|
||||||
*/
|
*/
|
||||||
if ((cols > MAX_LEVENSHTEIN_STRLEN + 1) || (rows > MAX_LEVENSHTEIN_STRLEN + 1))
|
if ((cols > MAX_LEVENSHTEIN_STRLEN + 1) || (rows > MAX_LEVENSHTEIN_STRLEN + 1))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -90,9 +89,9 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
MAX_LEVENSHTEIN_STRLEN)));
|
MAX_LEVENSHTEIN_STRLEN)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If either rows or cols is 0, the answer is the other value. This
|
* If either rows or cols is 0, the answer is the other value. This makes
|
||||||
* makes sense since it would take that many insertions the build a
|
* sense since it would take that many insertions the build a matching
|
||||||
* matching string
|
* string
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (cols == 0)
|
if (cols == 0)
|
||||||
|
@ -102,9 +101,8 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
PG_RETURN_INT32(cols);
|
PG_RETURN_INT32(cols);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocate two vectors of integers. One will be used for the "upper"
|
* Allocate two vectors of integers. One will be used for the "upper" row,
|
||||||
* row, the other for the "lower" row. Initialize the "upper" row to
|
* the other for the "lower" row. Initialize the "upper" row to 0..cols
|
||||||
* 0..cols
|
|
||||||
*/
|
*/
|
||||||
u_cells = palloc(sizeof(int) * cols);
|
u_cells = palloc(sizeof(int) * cols);
|
||||||
for (i = 0; i < cols; i++)
|
for (i = 0; i < cols; i++)
|
||||||
|
@ -119,14 +117,13 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
str_s0 = str_s;
|
str_s0 = str_s;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop through the rows, starting at row 1. Row 0 is used for the
|
* Loop through the rows, starting at row 1. Row 0 is used for the initial
|
||||||
* initial "upper" row.
|
* "upper" row.
|
||||||
*/
|
*/
|
||||||
for (j = 1; j < rows; j++)
|
for (j = 1; j < rows; j++)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We'll always start with col 1, and initialize lower row col 0
|
* We'll always start with col 1, and initialize lower row col 0 to j
|
||||||
* to j
|
|
||||||
*/
|
*/
|
||||||
l_cells[0] = j;
|
l_cells[0] = j;
|
||||||
|
|
||||||
|
@ -140,8 +137,7 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
/*
|
/*
|
||||||
* The "cost" value is 0 if the character at the current col
|
* The "cost" value is 0 if the character at the current col
|
||||||
* position in the source string, matches the character at the
|
* position in the source string, matches the character at the
|
||||||
* current row position in the target string; cost is 1
|
* current row position in the target string; cost is 1 otherwise.
|
||||||
* otherwise.
|
|
||||||
*/
|
*/
|
||||||
c = ((CHAREQ(str_s, str_t)) ? 0 : 1);
|
c = ((CHAREQ(str_s, str_t)) ? 0 : 1);
|
||||||
|
|
||||||
|
@ -172,8 +168,8 @@ levenshtein(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Lower row now becomes the upper row, and the upper row gets
|
* Lower row now becomes the upper row, and the upper row gets reused
|
||||||
* reused as the new lower row.
|
* as the new lower row.
|
||||||
*/
|
*/
|
||||||
tmp = u_cells;
|
tmp = u_cells;
|
||||||
u_cells = l_cells;
|
u_cells = l_cells;
|
||||||
|
@ -301,8 +297,8 @@ Lookahead(char *word, int how_far)
|
||||||
for (idx = 0; word[idx] != '\0' && idx < how_far; idx++);
|
for (idx = 0; word[idx] != '\0' && idx < how_far; idx++);
|
||||||
/* Edge forward in the string... */
|
/* Edge forward in the string... */
|
||||||
|
|
||||||
letter_ahead = word[idx]; /* idx will be either == to how_far or at
|
letter_ahead = word[idx]; /* idx will be either == to how_far or at the
|
||||||
* the end of the string */
|
* end of the string */
|
||||||
return letter_ahead;
|
return letter_ahead;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -453,11 +449,11 @@ _metaphone(
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* THOUGHT: It would be nice if, rather than having things
|
* THOUGHT: It would be nice if, rather than having things like...
|
||||||
* like... well, SCI. For SCI you encode the S, then have to
|
* well, SCI. For SCI you encode the S, then have to remember to skip
|
||||||
* remember to skip the C. So the phonome SCI invades both S and
|
* the C. So the phonome SCI invades both S and C. It would be
|
||||||
* C. It would be better, IMHO, to skip the C from the S part of
|
* better, IMHO, to skip the C from the S part of the encoding. Hell,
|
||||||
* the encoding. Hell, I'm trying it.
|
* I'm trying it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Ignore non-alphas */
|
/* Ignore non-alphas */
|
||||||
|
@ -478,9 +474,9 @@ _metaphone(
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* 'sh' if -CIA- or -CH, but not SCH, except SCHW. (SCHW
|
* 'sh' if -CIA- or -CH, but not SCH, except SCHW. (SCHW is
|
||||||
* is handled in S) S if -CI-, -CE- or -CY- dropped if
|
* handled in S) S if -CI-, -CE- or -CY- dropped if -SCI-,
|
||||||
* -SCI-, SCE-, -SCY- (handed in S) else K
|
* SCE-, -SCY- (handed in S) else K
|
||||||
*/
|
*/
|
||||||
case 'C':
|
case 'C':
|
||||||
if (MAKESOFT(Next_Letter))
|
if (MAKESOFT(Next_Letter))
|
||||||
|
@ -534,8 +530,8 @@ _metaphone(
|
||||||
/*
|
/*
|
||||||
* F if in -GH and not B--GH, D--GH, -H--GH, -H---GH else
|
* F if in -GH and not B--GH, D--GH, -H--GH, -H---GH else
|
||||||
* dropped if -GNED, -GN, else dropped if -DGE-, -DGI- or
|
* dropped if -GNED, -GN, else dropped if -DGE-, -DGI- or
|
||||||
* -DGY- (handled in D) else J if in -GE-, -GI, -GY and
|
* -DGY- (handled in D) else J if in -GE-, -GI, -GY and not GG
|
||||||
* not GG else K
|
* else K
|
||||||
*/
|
*/
|
||||||
case 'G':
|
case 'G':
|
||||||
if (Next_Letter == 'H')
|
if (Next_Letter == 'H')
|
||||||
|
@ -761,14 +757,17 @@ PG_FUNCTION_INFO_V1(difference);
|
||||||
Datum
|
Datum
|
||||||
difference(PG_FUNCTION_ARGS)
|
difference(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
char sndx1[SOUNDEX_LEN+1], sndx2[SOUNDEX_LEN+1];
|
char sndx1[SOUNDEX_LEN + 1],
|
||||||
int i, result;
|
sndx2[SOUNDEX_LEN + 1];
|
||||||
|
int i,
|
||||||
|
result;
|
||||||
|
|
||||||
_soundex(_textout(PG_GETARG_TEXT_P(0)), sndx1);
|
_soundex(_textout(PG_GETARG_TEXT_P(0)), sndx1);
|
||||||
_soundex(_textout(PG_GETARG_TEXT_P(1)), sndx2);
|
_soundex(_textout(PG_GETARG_TEXT_P(1)), sndx2);
|
||||||
|
|
||||||
result = 0;
|
result = 0;
|
||||||
for (i=0; i<SOUNDEX_LEN; i++) {
|
for (i = 0; i < SOUNDEX_LEN; i++)
|
||||||
|
{
|
||||||
if (sndx1[i] == sndx2[i])
|
if (sndx1[i] == sndx2[i])
|
||||||
result++;
|
result++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,7 @@ static PGARRAY *
|
||||||
ShrinkPGArray(PGARRAY * p)
|
ShrinkPGArray(PGARRAY * p)
|
||||||
{
|
{
|
||||||
PGARRAY *pnew;
|
PGARRAY *pnew;
|
||||||
|
|
||||||
/* get target size */
|
/* get target size */
|
||||||
int cb = PGARRAY_SIZE(p->items);
|
int cb = PGARRAY_SIZE(p->items);
|
||||||
|
|
||||||
|
@ -250,7 +251,8 @@ int_enum(PG_FUNCTION_ARGS)
|
||||||
fcinfo->flinfo->fn_extra = (void *) pc;
|
fcinfo->flinfo->fn_extra = (void *) pc;
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
}
|
}
|
||||||
else /* use existing working state */
|
else
|
||||||
|
/* use existing working state */
|
||||||
pc = (CTX *) fcinfo->flinfo->fn_extra;
|
pc = (CTX *) fcinfo->flinfo->fn_extra;
|
||||||
|
|
||||||
/* Are we done yet? */
|
/* Are we done yet? */
|
||||||
|
|
|
@ -378,8 +378,7 @@ g_int_picksplit(PG_FUNCTION_ARGS)
|
||||||
pfree(inter_d);
|
pfree(inter_d);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* are these a more promising split that what we've already
|
* are these a more promising split that what we've already seen?
|
||||||
* seen?
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (size_waste > waste || firsttime)
|
if (size_waste > waste || firsttime)
|
||||||
|
@ -430,15 +429,15 @@ g_int_picksplit(PG_FUNCTION_ARGS)
|
||||||
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
|
qsort((void *) costvector, maxoff, sizeof(SPLITCOST), comparecost);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now split up the regions between the two seeds. An important
|
* Now split up the regions between the two seeds. An important property
|
||||||
* property of this split algorithm is that the split vector v has the
|
* of this split algorithm is that the split vector v has the indices of
|
||||||
* indices of items to be split in order in its left and right
|
* items to be split in order in its left and right vectors. We exploit
|
||||||
* vectors. We exploit this property by doing a merge in the code
|
* this property by doing a merge in the code that actually splits the
|
||||||
* that actually splits the page.
|
* page.
|
||||||
*
|
*
|
||||||
* For efficiency, we also place the new index tuple in this loop. This
|
* For efficiency, we also place the new index tuple in this loop. This is
|
||||||
* is handled at the very end, when we have placed all the existing
|
* handled at the very end, when we have placed all the existing tuples
|
||||||
* tuples and i == maxoff + 1.
|
* and i == maxoff + 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -447,9 +446,9 @@ g_int_picksplit(PG_FUNCTION_ARGS)
|
||||||
i = costvector[j].pos;
|
i = costvector[j].pos;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've already decided where to place this item, just put it
|
* If we've already decided where to place this item, just put it on
|
||||||
* on the right list. Otherwise, we need to figure out which page
|
* the right list. Otherwise, we need to figure out which page needs
|
||||||
* needs the least enlargement in order to store the item.
|
* the least enlargement in order to store the item.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (i == seed_1)
|
if (i == seed_1)
|
||||||
|
|
|
@ -176,6 +176,7 @@ void *
|
||||||
myalloc(size_t size)
|
myalloc(size_t size)
|
||||||
{
|
{
|
||||||
void *ptr = malloc(size);
|
void *ptr = malloc(size);
|
||||||
|
|
||||||
if (!ptr)
|
if (!ptr)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "out of memory");
|
fprintf(stderr, "out of memory");
|
||||||
|
@ -188,6 +189,7 @@ char *
|
||||||
mystrdup(const char *str)
|
mystrdup(const char *str)
|
||||||
{
|
{
|
||||||
char *result = strdup(str);
|
char *result = strdup(str);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "out of memory");
|
fprintf(stderr, "out of memory");
|
||||||
|
@ -237,7 +239,8 @@ get_comma_elts(eary *eary)
|
||||||
{
|
{
|
||||||
char *ret,
|
char *ret,
|
||||||
*ptr;
|
*ptr;
|
||||||
int i, length = 0;
|
int i,
|
||||||
|
length = 0;
|
||||||
|
|
||||||
if (eary->num == 0)
|
if (eary->num == 0)
|
||||||
return mystrdup("");
|
return mystrdup("");
|
||||||
|
@ -303,7 +306,9 @@ sql_exec(PGconn *conn, const char *todo, bool quiet)
|
||||||
|
|
||||||
int nfields;
|
int nfields;
|
||||||
int nrows;
|
int nrows;
|
||||||
int i, j, l;
|
int i,
|
||||||
|
j,
|
||||||
|
l;
|
||||||
int *length;
|
int *length;
|
||||||
char *pad;
|
char *pad;
|
||||||
|
|
||||||
|
@ -425,8 +430,11 @@ void
|
||||||
sql_exec_searchtables(PGconn *conn, struct options * opts)
|
sql_exec_searchtables(PGconn *conn, struct options * opts)
|
||||||
{
|
{
|
||||||
char *todo;
|
char *todo;
|
||||||
char *qualifiers, *ptr;
|
char *qualifiers,
|
||||||
char *comma_oids, *comma_filenodes, *comma_tables;
|
*ptr;
|
||||||
|
char *comma_oids,
|
||||||
|
*comma_filenodes,
|
||||||
|
*comma_tables;
|
||||||
bool written = false;
|
bool written = false;
|
||||||
char *addfields = ",c.oid AS \"Oid\", nspname AS \"Schema\", spcname as \"Tablespace\" ";
|
char *addfields = ",c.oid AS \"Oid\", nspname AS \"Schema\", spcname as \"Tablespace\" ";
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* pg_buffercache_pages.c
|
* pg_buffercache_pages.c
|
||||||
* display some contents of the buffer cache
|
* display some contents of the buffer cache
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.5 2005/10/12 16:45:13 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pg_buffercache/pg_buffercache_pages.c,v 1.6 2005/10/15 02:49:05 momjian Exp $
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -99,8 +99,8 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
|
||||||
funcctx->attinmeta = TupleDescGetAttInMetadata(tupledesc);
|
funcctx->attinmeta = TupleDescGetAttInMetadata(tupledesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a function context for cross-call persistence
|
* Create a function context for cross-call persistence and initialize
|
||||||
* and initialize the buffer counters.
|
* the buffer counters.
|
||||||
*/
|
*/
|
||||||
fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext));
|
fctx = (BufferCachePagesContext *) palloc(sizeof(BufferCachePagesContext));
|
||||||
funcctx->max_calls = NBuffers;
|
funcctx->max_calls = NBuffers;
|
||||||
|
@ -171,9 +171,9 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use a temporary values array, initially pointing to
|
* Use a temporary values array, initially pointing to fctx->values,
|
||||||
* fctx->values, so it can be reassigned w/o losing the storage
|
* so it can be reassigned w/o losing the storage for subsequent
|
||||||
* for subsequent calls.
|
* calls.
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < NUM_BUFFERCACHE_PAGES_ELEM; j++)
|
for (j = 0; j < NUM_BUFFERCACHE_PAGES_ELEM; j++)
|
||||||
{
|
{
|
||||||
|
@ -182,8 +182,8 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set all fields except the bufferid to null if the buffer is
|
* Set all fields except the bufferid to null if the buffer is unused
|
||||||
* unused or not valid.
|
* or not valid.
|
||||||
*/
|
*/
|
||||||
if (fctx->record[i].blocknum == InvalidBlockNumber ||
|
if (fctx->record[i].blocknum == InvalidBlockNumber ||
|
||||||
fctx->record[i].isvalid == false)
|
fctx->record[i].isvalid == false)
|
||||||
|
@ -228,4 +228,3 @@ pg_buffercache_pages(PG_FUNCTION_ARGS)
|
||||||
SRF_RETURN_DONE(funcctx);
|
SRF_RETURN_DONE(funcctx);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.42 2005/10/07 15:34:17 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgbench/pgbench.c,v 1.43 2005/10/15 02:49:06 momjian Exp $
|
||||||
*
|
*
|
||||||
* pgbench: a simple benchmark program for PostgreSQL
|
* pgbench: a simple benchmark program for PostgreSQL
|
||||||
* written by Tatsuo Ishii
|
* written by Tatsuo Ishii
|
||||||
|
@ -55,8 +55,7 @@ extern int optind;
|
||||||
#define MAXCLIENTS 1024 /* max number of clients allowed */
|
#define MAXCLIENTS 1024 /* max number of clients allowed */
|
||||||
|
|
||||||
int nclients = 1; /* default number of simulated clients */
|
int nclients = 1; /* default number of simulated clients */
|
||||||
int nxacts = 10; /* default number of transactions per
|
int nxacts = 10; /* default number of transactions per clients */
|
||||||
* clients */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* scaling factor. for example, tps = 10 will make 1000000 tuples of
|
* scaling factor. for example, tps = 10 will make 1000000 tuples of
|
||||||
|
@ -78,8 +77,7 @@ bool use_log; /* log transaction latencies to a file */
|
||||||
|
|
||||||
int remains; /* number of remaining clients */
|
int remains; /* number of remaining clients */
|
||||||
|
|
||||||
int is_connect; /* establish connection for each
|
int is_connect; /* establish connection for each transaction */
|
||||||
* transaction */
|
|
||||||
|
|
||||||
char *pghost = "";
|
char *pghost = "";
|
||||||
char *pgport = NULL;
|
char *pgport = NULL;
|
||||||
|
@ -107,8 +105,8 @@ typedef struct
|
||||||
int state; /* state No. */
|
int state; /* state No. */
|
||||||
int cnt; /* xacts count */
|
int cnt; /* xacts count */
|
||||||
int ecnt; /* error count */
|
int ecnt; /* error count */
|
||||||
int listen; /* 0 indicates that an async query has
|
int listen; /* 0 indicates that an async query has been
|
||||||
* been sent */
|
* sent */
|
||||||
Variable *variables; /* array of variable definitions */
|
Variable *variables; /* array of variable definitions */
|
||||||
int nvariables;
|
int nvariables;
|
||||||
struct timeval txn_begin; /* used for measuring latencies */
|
struct timeval txn_begin; /* used for measuring latencies */
|
||||||
|
@ -341,15 +339,19 @@ putVariable(CState * st, char *name, char *value)
|
||||||
static char *
|
static char *
|
||||||
assignVariables(CState * st, char *sql)
|
assignVariables(CState * st, char *sql)
|
||||||
{
|
{
|
||||||
int i, j;
|
int i,
|
||||||
char *p, *name, *val;
|
j;
|
||||||
|
char *p,
|
||||||
|
*name,
|
||||||
|
*val;
|
||||||
void *tmp;
|
void *tmp;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
while ((p = strchr(&sql[i], ':')) != NULL)
|
while ((p = strchr(&sql[i], ':')) != NULL)
|
||||||
{
|
{
|
||||||
i = j = p - sql;
|
i = j = p - sql;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
i++;
|
i++;
|
||||||
} while (isalnum((unsigned char) sql[i]) || sql[i] == '_');
|
} while (isalnum((unsigned char) sql[i]) || sql[i] == '_');
|
||||||
if (i == j + 1)
|
if (i == j + 1)
|
||||||
|
@ -426,8 +428,7 @@ doCustom(CState * state, int n, int debug)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* transaction finished: record the time it took in the
|
* transaction finished: record the time it took in the log
|
||||||
* log
|
|
||||||
*/
|
*/
|
||||||
if (use_log && commands[st->state + 1] == NULL)
|
if (use_log && commands[st->state + 1] == NULL)
|
||||||
{
|
{
|
||||||
|
@ -531,7 +532,8 @@ doCustom(CState * state, int n, int debug)
|
||||||
}
|
}
|
||||||
else if (commands[st->state]->type == META_COMMAND)
|
else if (commands[st->state]->type == META_COMMAND)
|
||||||
{
|
{
|
||||||
int argc = commands[st->state]->argc, i;
|
int argc = commands[st->state]->argc,
|
||||||
|
i;
|
||||||
char **argv = commands[st->state]->argv;
|
char **argv = commands[st->state]->argv;
|
||||||
|
|
||||||
if (debug)
|
if (debug)
|
||||||
|
@ -755,7 +757,8 @@ process_commands(char *buf)
|
||||||
|
|
||||||
Command *my_commands;
|
Command *my_commands;
|
||||||
int j;
|
int j;
|
||||||
char *p, *tok;
|
char *p,
|
||||||
|
*tok;
|
||||||
|
|
||||||
if ((p = strchr(buf, '\n')) != NULL)
|
if ((p = strchr(buf, '\n')) != NULL)
|
||||||
*p = '\0';
|
*p = '\0';
|
||||||
|
@ -797,7 +800,8 @@ process_commands(char *buf)
|
||||||
|
|
||||||
if (strcasecmp(my_commands->argv[0], "setrandom") == 0)
|
if (strcasecmp(my_commands->argv[0], "setrandom") == 0)
|
||||||
{
|
{
|
||||||
int min, max;
|
int min,
|
||||||
|
max;
|
||||||
|
|
||||||
if (my_commands->argc < 4)
|
if (my_commands->argc < 4)
|
||||||
{
|
{
|
||||||
|
@ -1016,20 +1020,18 @@ main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
int is_init_mode = 0; /* initialize mode? */
|
int is_init_mode = 0; /* initialize mode? */
|
||||||
int is_no_vacuum = 0; /* no vacuum at all before
|
int is_no_vacuum = 0; /* no vacuum at all before testing? */
|
||||||
* testing? */
|
|
||||||
int is_full_vacuum = 0; /* do full vacuum before testing? */
|
int is_full_vacuum = 0; /* do full vacuum before testing? */
|
||||||
int debug = 0; /* debug flag */
|
int debug = 0; /* debug flag */
|
||||||
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT
|
int ttype = 0; /* transaction type. 0: TPC-B, 1: SELECT only,
|
||||||
* only, 2: skip update of branches and
|
* 2: skip update of branches and tellers */
|
||||||
* tellers */
|
|
||||||
char *filename = NULL;
|
char *filename = NULL;
|
||||||
|
|
||||||
static CState *state; /* status of clients */
|
static CState *state; /* status of clients */
|
||||||
|
|
||||||
struct timeval tv1; /* start up time */
|
struct timeval tv1; /* start up time */
|
||||||
struct timeval tv2; /* after establishing all connections to
|
struct timeval tv2; /* after establishing all connections to the
|
||||||
* the backend */
|
* backend */
|
||||||
struct timeval tv3; /* end time */
|
struct timeval tv3; /* end time */
|
||||||
|
|
||||||
int i;
|
int i;
|
||||||
|
@ -1105,7 +1107,8 @@ main(int argc, char **argv)
|
||||||
fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
|
fprintf(stderr, "Use limit/ulimt to increase the limit before using pgbench.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
#endif /* #if !(defined(__CYGWIN__) || defined(__MINGW32__)) */
|
#endif /* #if !(defined(__CYGWIN__) ||
|
||||||
|
* defined(__MINGW32__)) */
|
||||||
break;
|
break;
|
||||||
case 'C':
|
case 'C':
|
||||||
is_connect = 1;
|
is_connect = 1;
|
||||||
|
|
|
@ -520,7 +520,6 @@ extern void _BF_body_r(BF_ctx * ctx);
|
||||||
|
|
||||||
#define BF_body() \
|
#define BF_body() \
|
||||||
_BF_body_r(&data.ctx);
|
_BF_body_r(&data.ctx);
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define BF_body() \
|
#define BF_body() \
|
||||||
|
|
|
@ -246,8 +246,8 @@ des_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert the inverted S-boxes into 4 arrays of 8 bits. Each will
|
* Convert the inverted S-boxes into 4 arrays of 8 bits. Each will handle
|
||||||
* handle 12 bits of the S-box input.
|
* 12 bits of the S-box input.
|
||||||
*/
|
*/
|
||||||
for (b = 0; b < 4; b++)
|
for (b = 0; b < 4; b++)
|
||||||
for (i = 0; i < 64; i++)
|
for (i = 0; i < 64; i++)
|
||||||
|
@ -267,8 +267,8 @@ des_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invert the key permutation and initialise the inverted key
|
* Invert the key permutation and initialise the inverted key compression
|
||||||
* compression permutation.
|
* permutation.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < 56; i++)
|
for (i = 0; i < 56; i++)
|
||||||
{
|
{
|
||||||
|
@ -284,8 +284,8 @@ des_init(void)
|
||||||
inv_comp_perm[comp_perm[i] - 1] = i;
|
inv_comp_perm[comp_perm[i] - 1] = i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up the OR-mask arrays for the initial and final permutations,
|
* Set up the OR-mask arrays for the initial and final permutations, and
|
||||||
* and for the key initial and compression permutations.
|
* for the key initial and compression permutations.
|
||||||
*/
|
*/
|
||||||
for (k = 0; k < 8; k++)
|
for (k = 0; k < 8; k++)
|
||||||
{
|
{
|
||||||
|
@ -347,8 +347,8 @@ des_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Invert the P-box permutation, and convert into OR-masks for
|
* Invert the P-box permutation, and convert into OR-masks for handling
|
||||||
* handling the output of the S-box arrays setup above.
|
* the output of the S-box arrays setup above.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < 32; i++)
|
for (i = 0; i < 32; i++)
|
||||||
un_pbox[pbox[i] - 1] = i;
|
un_pbox[pbox[i] - 1] = i;
|
||||||
|
@ -411,9 +411,9 @@ des_setkey(const char *key)
|
||||||
&& rawkey1 == old_rawkey1)
|
&& rawkey1 == old_rawkey1)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Already setup for this key. This optimisation fails on a zero
|
* Already setup for this key. This optimisation fails on a zero key
|
||||||
* key (which is weak and has bad parity anyway) in order to
|
* (which is weak and has bad parity anyway) in order to simplify the
|
||||||
* simplify the starting conditions.
|
* starting conditions.
|
||||||
*/
|
*/
|
||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
@ -560,16 +560,16 @@ do_des(uint32 l_in, uint32 r_in, uint32 *l_out, uint32 *r_out, int count)
|
||||||
| ((r & 0x80000000) >> 31);
|
| ((r & 0x80000000) >> 31);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do salting for crypt() and friends, and XOR with the
|
* Do salting for crypt() and friends, and XOR with the permuted
|
||||||
* permuted key.
|
* key.
|
||||||
*/
|
*/
|
||||||
f = (r48l ^ r48r) & saltbits;
|
f = (r48l ^ r48r) & saltbits;
|
||||||
r48l ^= f ^ *kl++;
|
r48l ^= f ^ *kl++;
|
||||||
r48r ^= f ^ *kr++;
|
r48r ^= f ^ *kr++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Do sbox lookups (which shrink it back to 32 bits) and do
|
* Do sbox lookups (which shrink it back to 32 bits) and do the
|
||||||
* the pbox permutation at the same time.
|
* pbox permutation at the same time.
|
||||||
*/
|
*/
|
||||||
f = psbox[0][m_sbox[0][r48l >> 12]]
|
f = psbox[0][m_sbox[0][r48l >> 12]]
|
||||||
| psbox[1][m_sbox[1][r48l & 0xfff]]
|
| psbox[1][m_sbox[1][r48l & 0xfff]]
|
||||||
|
@ -660,8 +660,8 @@ px_crypt_des(const char *key, const char *setting)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copy the key, shifting each character up by one bit and padding
|
* Copy the key, shifting each character up by one bit and padding with
|
||||||
* with zeros.
|
* zeros.
|
||||||
*/
|
*/
|
||||||
q = (uint8 *) keybuf;
|
q = (uint8 *) keybuf;
|
||||||
while (q - (uint8 *) keybuf - 8)
|
while (q - (uint8 *) keybuf - 8)
|
||||||
|
@ -706,10 +706,10 @@ px_crypt_des(const char *key, const char *setting)
|
||||||
strncpy(output, setting, 9);
|
strncpy(output, setting, 9);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Double check that we weren't given a short setting. If we were,
|
* Double check that we weren't given a short setting. If we were, the
|
||||||
* the above code will probably have created wierd values for
|
* above code will probably have created wierd values for count and
|
||||||
* count and salt, but we don't really care. Just make sure the
|
* salt, but we don't really care. Just make sure the output string
|
||||||
* output string doesn't have an extra NUL in it.
|
* doesn't have an extra NUL in it.
|
||||||
*/
|
*/
|
||||||
output[9] = '\0';
|
output[9] = '\0';
|
||||||
p = output + strlen(output);
|
p = output + strlen(output);
|
||||||
|
@ -728,9 +728,9 @@ px_crypt_des(const char *key, const char *setting)
|
||||||
output[0] = setting[0];
|
output[0] = setting[0];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the encrypted password that the salt was extracted from is
|
* If the encrypted password that the salt was extracted from is only
|
||||||
* only 1 character long, the salt will be corrupted. We need to
|
* 1 character long, the salt will be corrupted. We need to ensure
|
||||||
* ensure that the output string doesn't have an extra NUL in it!
|
* that the output string doesn't have an extra NUL in it!
|
||||||
*/
|
*/
|
||||||
output[1] = setting[1] ? setting[1] : output[0];
|
output[1] = setting[1] ? setting[1] : output[0];
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $
|
* $FreeBSD: src/lib/libcrypt/crypt-md5.c,v 1.5 1999/12/17 20:21:45 peter Exp $
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-md5.c,v 1.5 2005/09/24 19:14:04 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/crypt-md5.c,v 1.6 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -24,9 +24,9 @@
|
||||||
char *
|
char *
|
||||||
px_crypt_md5(const char *pw, const char *salt, char *passwd, unsigned dstlen)
|
px_crypt_md5(const char *pw, const char *salt, char *passwd, unsigned dstlen)
|
||||||
{
|
{
|
||||||
static char *magic = "$1$"; /* This string is magic for this
|
static char *magic = "$1$"; /* This string is magic for this algorithm.
|
||||||
* algorithm. Having it this way, we can
|
* Having it this way, we can get get better
|
||||||
* get get better later on */
|
* later on */
|
||||||
static char *p;
|
static char *p;
|
||||||
static const char *sp,
|
static const char *sp,
|
||||||
*ep;
|
*ep;
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.4 2005/07/18 17:12:54 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.c,v 1.5 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -114,7 +114,8 @@
|
||||||
#define MD_CTX SHA256_CTX
|
#define MD_CTX SHA256_CTX
|
||||||
#define CIPH_CTX rijndael_ctx
|
#define CIPH_CTX rijndael_ctx
|
||||||
|
|
||||||
struct fortuna_state {
|
struct fortuna_state
|
||||||
|
{
|
||||||
uint8 counter[CIPH_BLOCK];
|
uint8 counter[CIPH_BLOCK];
|
||||||
uint8 result[CIPH_BLOCK];
|
uint8 result[CIPH_BLOCK];
|
||||||
uint8 key[BLOCK];
|
uint8 key[BLOCK];
|
||||||
|
@ -137,29 +138,35 @@ typedef struct fortuna_state FState;
|
||||||
* - No memory allocations.
|
* - No memory allocations.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void ciph_init(CIPH_CTX *ctx, const uint8 *key, int klen)
|
static void
|
||||||
|
ciph_init(CIPH_CTX * ctx, const uint8 *key, int klen)
|
||||||
{
|
{
|
||||||
rijndael_set_key(ctx, (const uint32 *) key, klen, 1);
|
rijndael_set_key(ctx, (const uint32 *) key, klen, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ciph_encrypt(CIPH_CTX *ctx, const uint8 *in, uint8 *out)
|
static void
|
||||||
|
ciph_encrypt(CIPH_CTX * ctx, const uint8 *in, uint8 *out)
|
||||||
{
|
{
|
||||||
rijndael_encrypt(ctx, (const uint32 *) in, (uint32 *) out);
|
rijndael_encrypt(ctx, (const uint32 *) in, (uint32 *) out);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void md_init(MD_CTX *ctx)
|
static void
|
||||||
|
md_init(MD_CTX * ctx)
|
||||||
{
|
{
|
||||||
SHA256_Init(ctx);
|
SHA256_Init(ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void md_update(MD_CTX *ctx, const uint8 *data, int len)
|
static void
|
||||||
|
md_update(MD_CTX * ctx, const uint8 *data, int len)
|
||||||
{
|
{
|
||||||
SHA256_Update(ctx, data, len);
|
SHA256_Update(ctx, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void md_result(MD_CTX *ctx, uint8 *dst)
|
static void
|
||||||
|
md_result(MD_CTX * ctx, uint8 *dst)
|
||||||
{
|
{
|
||||||
SHA256_CTX tmp;
|
SHA256_CTX tmp;
|
||||||
|
|
||||||
memcpy(&tmp, ctx, sizeof(*ctx));
|
memcpy(&tmp, ctx, sizeof(*ctx));
|
||||||
SHA256_Final(dst, &tmp);
|
SHA256_Final(dst, &tmp);
|
||||||
memset(&tmp, 0, sizeof(tmp));
|
memset(&tmp, 0, sizeof(tmp));
|
||||||
|
@ -168,9 +175,11 @@ static void md_result(MD_CTX *ctx, uint8 *dst)
|
||||||
/*
|
/*
|
||||||
* initialize state
|
* initialize state
|
||||||
*/
|
*/
|
||||||
static void init_state(FState *st)
|
static void
|
||||||
|
init_state(FState * st)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
memset(st, 0, sizeof(*st));
|
memset(st, 0, sizeof(*st));
|
||||||
for (i = 0; i < NUM_POOLS; i++)
|
for (i = 0; i < NUM_POOLS; i++)
|
||||||
md_init(&st->pool[i]);
|
md_init(&st->pool[i]);
|
||||||
|
@ -180,9 +189,11 @@ static void init_state(FState *st)
|
||||||
* Endianess does not matter.
|
* Endianess does not matter.
|
||||||
* It just needs to change without repeating.
|
* It just needs to change without repeating.
|
||||||
*/
|
*/
|
||||||
static void inc_counter(FState *st)
|
static void
|
||||||
|
inc_counter(FState * st)
|
||||||
{
|
{
|
||||||
uint32 *val = (uint32 *) st->counter;
|
uint32 *val = (uint32 *) st->counter;
|
||||||
|
|
||||||
if (++val[0])
|
if (++val[0])
|
||||||
return;
|
return;
|
||||||
if (++val[1])
|
if (++val[1])
|
||||||
|
@ -195,7 +206,8 @@ static void inc_counter(FState *st)
|
||||||
/*
|
/*
|
||||||
* This is called 'cipher in counter mode'.
|
* This is called 'cipher in counter mode'.
|
||||||
*/
|
*/
|
||||||
static void encrypt_counter(FState *st, uint8 *dst)
|
static void
|
||||||
|
encrypt_counter(FState * st, uint8 *dst)
|
||||||
{
|
{
|
||||||
ciph_encrypt(&st->ciph, st->counter, dst);
|
ciph_encrypt(&st->ciph, st->counter, dst);
|
||||||
inc_counter(st);
|
inc_counter(st);
|
||||||
|
@ -206,7 +218,8 @@ static void encrypt_counter(FState *st, uint8 *dst)
|
||||||
* The time between reseed must be at least RESEED_INTERVAL
|
* The time between reseed must be at least RESEED_INTERVAL
|
||||||
* microseconds.
|
* microseconds.
|
||||||
*/
|
*/
|
||||||
static int too_often(FState *st)
|
static int
|
||||||
|
too_often(FState * st)
|
||||||
{
|
{
|
||||||
int ok;
|
int ok;
|
||||||
struct timeval tv;
|
struct timeval tv;
|
||||||
|
@ -229,7 +242,8 @@ static int too_often(FState *st)
|
||||||
/*
|
/*
|
||||||
* generate new key from all the pools
|
* generate new key from all the pools
|
||||||
*/
|
*/
|
||||||
static void reseed(FState *st)
|
static void
|
||||||
|
reseed(FState * st)
|
||||||
{
|
{
|
||||||
unsigned k;
|
unsigned k;
|
||||||
unsigned n;
|
unsigned n;
|
||||||
|
@ -240,8 +254,7 @@ static void reseed(FState *st)
|
||||||
st->pool0_bytes = 0;
|
st->pool0_bytes = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Both #0 and #1 reseed would use only pool 0.
|
* Both #0 and #1 reseed would use only pool 0. Just skip #0 then.
|
||||||
* Just skip #0 then.
|
|
||||||
*/
|
*/
|
||||||
n = ++st->reseed_count;
|
n = ++st->reseed_count;
|
||||||
|
|
||||||
|
@ -249,7 +262,8 @@ static void reseed(FState *st)
|
||||||
* The goal: use k-th pool only 1/(2^k) of the time.
|
* The goal: use k-th pool only 1/(2^k) of the time.
|
||||||
*/
|
*/
|
||||||
md_init(&key_md);
|
md_init(&key_md);
|
||||||
for (k = 0; k < NUM_POOLS; k++) {
|
for (k = 0; k < NUM_POOLS; k++)
|
||||||
|
{
|
||||||
md_result(&st->pool[k], buf);
|
md_result(&st->pool[k], buf);
|
||||||
md_update(&key_md, buf, BLOCK);
|
md_update(&key_md, buf, BLOCK);
|
||||||
|
|
||||||
|
@ -274,7 +288,8 @@ static void reseed(FState *st)
|
||||||
/*
|
/*
|
||||||
* Pick a random pool. This uses key bytes as random source.
|
* Pick a random pool. This uses key bytes as random source.
|
||||||
*/
|
*/
|
||||||
static unsigned get_rand_pool(FState *st)
|
static unsigned
|
||||||
|
get_rand_pool(FState * st)
|
||||||
{
|
{
|
||||||
unsigned rnd;
|
unsigned rnd;
|
||||||
|
|
||||||
|
@ -293,7 +308,8 @@ static unsigned get_rand_pool(FState *st)
|
||||||
/*
|
/*
|
||||||
* update pools
|
* update pools
|
||||||
*/
|
*/
|
||||||
static void add_entropy(FState *st, const uint8 *data, unsigned len)
|
static void
|
||||||
|
add_entropy(FState * st, const uint8 *data, unsigned len)
|
||||||
{
|
{
|
||||||
unsigned pos;
|
unsigned pos;
|
||||||
uint8 hash[BLOCK];
|
uint8 hash[BLOCK];
|
||||||
|
@ -305,8 +321,7 @@ static void add_entropy(FState *st, const uint8 *data, unsigned len)
|
||||||
md_result(&md, hash);
|
md_result(&md, hash);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure the pool 0 is initialized,
|
* Make sure the pool 0 is initialized, then update randomly.
|
||||||
* then update randomly.
|
|
||||||
*/
|
*/
|
||||||
if (st->reseed_count == 0 && st->pool0_bytes < POOL0_FILL)
|
if (st->reseed_count == 0 && st->pool0_bytes < POOL0_FILL)
|
||||||
pos = 0;
|
pos = 0;
|
||||||
|
@ -324,7 +339,8 @@ static void add_entropy(FState *st, const uint8 *data, unsigned len)
|
||||||
/*
|
/*
|
||||||
* Just take 2 next blocks as new key
|
* Just take 2 next blocks as new key
|
||||||
*/
|
*/
|
||||||
static void rekey(FState *st)
|
static void
|
||||||
|
rekey(FState * st)
|
||||||
{
|
{
|
||||||
encrypt_counter(st, st->key);
|
encrypt_counter(st, st->key);
|
||||||
encrypt_counter(st, st->key + CIPH_BLOCK);
|
encrypt_counter(st, st->key + CIPH_BLOCK);
|
||||||
|
@ -336,7 +352,8 @@ static void rekey(FState *st)
|
||||||
* In case it does not, slow down the attacker by initialising
|
* In case it does not, slow down the attacker by initialising
|
||||||
* the couter to random value.
|
* the couter to random value.
|
||||||
*/
|
*/
|
||||||
static void init_counter(FState *st)
|
static void
|
||||||
|
init_counter(FState * st)
|
||||||
{
|
{
|
||||||
/* Use next block as counter. */
|
/* Use next block as counter. */
|
||||||
encrypt_counter(st, st->counter);
|
encrypt_counter(st, st->counter);
|
||||||
|
@ -348,7 +365,8 @@ static void init_counter(FState *st)
|
||||||
st->counter_init = 1;
|
st->counter_init = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void extract_data(FState *st, unsigned count, uint8 *dst)
|
static void
|
||||||
|
extract_data(FState * st, unsigned count, uint8 *dst)
|
||||||
{
|
{
|
||||||
unsigned n;
|
unsigned n;
|
||||||
unsigned block_nr = 0;
|
unsigned block_nr = 0;
|
||||||
|
@ -361,7 +379,8 @@ static void extract_data(FState *st, unsigned count, uint8 *dst)
|
||||||
if (!st->counter_init)
|
if (!st->counter_init)
|
||||||
init_counter(st);
|
init_counter(st);
|
||||||
|
|
||||||
while (count > 0) {
|
while (count > 0)
|
||||||
|
{
|
||||||
/* produce bytes */
|
/* produce bytes */
|
||||||
encrypt_counter(st, st->result);
|
encrypt_counter(st, st->result);
|
||||||
|
|
||||||
|
@ -393,7 +412,8 @@ static void extract_data(FState *st, unsigned count, uint8 *dst)
|
||||||
static FState main_state;
|
static FState main_state;
|
||||||
static int init_done = 0;
|
static int init_done = 0;
|
||||||
|
|
||||||
void fortuna_add_entropy(const uint8 *data, unsigned len)
|
void
|
||||||
|
fortuna_add_entropy(const uint8 *data, unsigned len)
|
||||||
{
|
{
|
||||||
if (!init_done)
|
if (!init_done)
|
||||||
{
|
{
|
||||||
|
@ -405,7 +425,8 @@ void fortuna_add_entropy(const uint8 *data, unsigned len)
|
||||||
add_entropy(&main_state, data, len);
|
add_entropy(&main_state, data, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void fortuna_get_bytes(unsigned len, uint8 *dst)
|
void
|
||||||
|
fortuna_get_bytes(unsigned len, uint8 *dst)
|
||||||
{
|
{
|
||||||
if (!init_done)
|
if (!init_done)
|
||||||
{
|
{
|
||||||
|
@ -416,4 +437,3 @@ void fortuna_get_bytes(unsigned len, uint8 *dst)
|
||||||
return;
|
return;
|
||||||
extract_data(&main_state, len, dst);
|
extract_data(&main_state, len, dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.h,v 1.2 2005/07/18 17:12:54 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/fortuna.h,v 1.3 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __FORTUNA_H
|
#ifndef __FORTUNA_H
|
||||||
|
@ -36,4 +36,3 @@ void fortuna_get_bytes(unsigned len, uint8 *dst);
|
||||||
void fortuna_add_entropy(const uint8 *data, unsigned len);
|
void fortuna_add_entropy(const uint8 *data, unsigned len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.22 2005/07/18 17:12:54 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/internal.c,v 1.23 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -240,6 +240,7 @@ int_sha256_free(PX_MD * h)
|
||||||
px_free(ctx);
|
px_free(ctx);
|
||||||
px_free(h);
|
px_free(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* SHA384 */
|
/* SHA384 */
|
||||||
|
|
||||||
static unsigned
|
static unsigned
|
||||||
|
@ -838,7 +839,8 @@ px_get_pseudo_random_bytes(uint8 *dst, unsigned count)
|
||||||
static time_t seed_time = 0;
|
static time_t seed_time = 0;
|
||||||
static time_t check_time = 0;
|
static time_t check_time = 0;
|
||||||
|
|
||||||
static void system_reseed(void)
|
static void
|
||||||
|
system_reseed(void)
|
||||||
{
|
{
|
||||||
uint8 buf[1024];
|
uint8 buf[1024];
|
||||||
int n;
|
int n;
|
||||||
|
@ -890,4 +892,3 @@ px_add_entropy(const uint8 *data, unsigned count)
|
||||||
fortuna_add_entropy(data, count);
|
fortuna_add_entropy(data, count);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/mbuf.c,v 1.2 2005/07/11 15:07:59 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/mbuf.c,v 1.3 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -166,7 +166,8 @@ mbuf_grab(MBuf * mbuf, int len, uint8 **data_p)
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mbuf_rewind(MBuf *mbuf)
|
int
|
||||||
|
mbuf_rewind(MBuf * mbuf)
|
||||||
{
|
{
|
||||||
mbuf->read_pos = mbuf->data;
|
mbuf->read_pos = mbuf->data;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -261,6 +262,7 @@ int
|
||||||
pullf_read(PullFilter * pf, int len, uint8 **data_p)
|
pullf_read(PullFilter * pf, int len, uint8 **data_p)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (pf->op->pull)
|
if (pf->op->pull)
|
||||||
{
|
{
|
||||||
if (pf->buflen && len > pf->buflen)
|
if (pf->buflen && len > pf->buflen)
|
||||||
|
@ -276,7 +278,8 @@ pullf_read(PullFilter * pf, int len, uint8 **data_p)
|
||||||
int
|
int
|
||||||
pullf_read_max(PullFilter * pf, int len, uint8 **data_p, uint8 *tmpbuf)
|
pullf_read_max(PullFilter * pf, int len, uint8 **data_p, uint8 *tmpbuf)
|
||||||
{
|
{
|
||||||
int res, total;
|
int res,
|
||||||
|
total;
|
||||||
uint8 *tmp;
|
uint8 *tmp;
|
||||||
|
|
||||||
res = pullf_read(pf, len, data_p);
|
res = pullf_read(pf, len, data_p);
|
||||||
|
@ -289,7 +292,8 @@ pullf_read_max(PullFilter * pf, int len, uint8 **data_p, uint8 *tmpbuf)
|
||||||
len -= res;
|
len -= res;
|
||||||
total = res;
|
total = res;
|
||||||
|
|
||||||
while (len > 0) {
|
while (len > 0)
|
||||||
|
{
|
||||||
res = pullf_read(pf, len, &tmp);
|
res = pullf_read(pf, len, &tmp);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
{
|
{
|
||||||
|
@ -308,10 +312,12 @@ pullf_read_max(PullFilter * pf, int len, uint8 **data_p, uint8 *tmpbuf)
|
||||||
/*
|
/*
|
||||||
* caller wants exatly len bytes and dont bother with references
|
* caller wants exatly len bytes and dont bother with references
|
||||||
*/
|
*/
|
||||||
int pullf_read_fixed(PullFilter *src, int len, uint8 *dst)
|
int
|
||||||
|
pullf_read_fixed(PullFilter * src, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
uint8 *p;
|
uint8 *p;
|
||||||
|
|
||||||
res = pullf_read_max(src, len, &p, dst);
|
res = pullf_read_max(src, len, &p, dst);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
@ -333,6 +339,7 @@ pull_from_mbuf(void *arg, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen)
|
uint8 **data_p, uint8 *buf, int buflen)
|
||||||
{
|
{
|
||||||
MBuf *mbuf = arg;
|
MBuf *mbuf = arg;
|
||||||
|
|
||||||
return mbuf_grab(mbuf, len, data_p);
|
return mbuf_grab(mbuf, len, data_p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -549,8 +556,8 @@ static const struct PushFilterOps mbuf_filter = {
|
||||||
NULL, push_into_mbuf, NULL, NULL
|
NULL, push_into_mbuf, NULL, NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
int pushf_create_mbuf_writer(PushFilter **res, MBuf *dst)
|
int
|
||||||
|
pushf_create_mbuf_writer(PushFilter ** res, MBuf * dst)
|
||||||
{
|
{
|
||||||
return pushf_create(res, &mbuf_filter, dst, NULL);
|
return pushf_create(res, &mbuf_filter, dst, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/mbuf.h,v 1.1 2005/07/10 13:46:28 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/mbuf.h,v 1.2 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PX_MBUF_H
|
#ifndef __PX_MBUF_H
|
||||||
|
@ -40,13 +40,15 @@ typedef struct PullFilterOps PullFilterOps;
|
||||||
|
|
||||||
struct PushFilterOps
|
struct PushFilterOps
|
||||||
{
|
{
|
||||||
/* should return needed buffer size, 0- no buffering, <0 on error
|
/*
|
||||||
* if NULL, no buffering, and priv=init_arg
|
* should return needed buffer size, 0- no buffering, <0 on error if NULL,
|
||||||
|
* no buffering, and priv=init_arg
|
||||||
*/
|
*/
|
||||||
int (*init) (PushFilter * next, void *init_arg, void **priv_p);
|
int (*init) (PushFilter * next, void *init_arg, void **priv_p);
|
||||||
/* send data to next. should consume all?
|
|
||||||
* if null, it will be simply copied (in-place)
|
/*
|
||||||
* returns 0 on error
|
* send data to next. should consume all? if null, it will be simply
|
||||||
|
* copied (in-place) returns 0 on error
|
||||||
*/
|
*/
|
||||||
int (*push) (PushFilter * next, void *priv,
|
int (*push) (PushFilter * next, void *priv,
|
||||||
const uint8 *src, int len);
|
const uint8 *src, int len);
|
||||||
|
@ -56,13 +58,15 @@ struct PushFilterOps
|
||||||
|
|
||||||
struct PullFilterOps
|
struct PullFilterOps
|
||||||
{
|
{
|
||||||
/* should return needed buffer size, 0- no buffering, <0 on error
|
/*
|
||||||
* if NULL, no buffering, and priv=init_arg
|
* should return needed buffer size, 0- no buffering, <0 on error if NULL,
|
||||||
|
* no buffering, and priv=init_arg
|
||||||
*/
|
*/
|
||||||
int (*init) (void **priv_p, void *init_arg, PullFilter * src);
|
int (*init) (void **priv_p, void *init_arg, PullFilter * src);
|
||||||
/* request data from src, put result ptr to data_p
|
|
||||||
* can use ptr from src or use buf as work area
|
/*
|
||||||
* if NULL in-place copy
|
* request data from src, put result ptr to data_p can use ptr from src or
|
||||||
|
* use buf as work area if NULL in-place copy
|
||||||
*/
|
*/
|
||||||
int (*pull) (void *priv, PullFilter * src, int len,
|
int (*pull) (void *priv, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen);
|
uint8 **data_p, uint8 *buf, int buflen);
|
||||||
|
@ -118,4 +122,3 @@ int pullf_create_mbuf_reader(PullFilter ** pf_p, MBuf * mbuf);
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif /* __PX_MBUF_H */
|
#endif /* __PX_MBUF_H */
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $PostgreSQL: pgsql/contrib/pgcrypto/md5.h,v 1.8 2003/11/29 22:39:28 pgsql Exp $ */
|
/* $PostgreSQL: pgsql/contrib/pgcrypto/md5.h,v 1.9 2005/10/15 02:49:06 momjian Exp $ */
|
||||||
/* $KAME: md5.h,v 1.3 2000/02/22 14:01:18 itojun Exp $ */
|
/* $KAME: md5.h,v 1.3 2000/02/22 14:01:18 itojun Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.25 2005/07/12 20:27:42 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/openssl.c,v 1.26 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -53,7 +53,6 @@
|
||||||
|
|
||||||
/* Yes, it does. */
|
/* Yes, it does. */
|
||||||
#include <openssl/aes.h>
|
#include <openssl/aes.h>
|
||||||
|
|
||||||
#else /* old OPENSSL */
|
#else /* old OPENSSL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -91,7 +90,6 @@
|
||||||
memcpy(iv, (src) + (len) - 16, 16); \
|
memcpy(iv, (src) + (len) - 16, 16); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#endif /* old OPENSSL */
|
#endif /* old OPENSSL */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -157,8 +155,8 @@ digest_finish(PX_MD * h, uint8 *dst)
|
||||||
EVP_DigestFinal(ctx, dst, NULL);
|
EVP_DigestFinal(ctx, dst, NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Some builds of 0.9.7x clear all of ctx in EVP_DigestFinal.
|
* Some builds of 0.9.7x clear all of ctx in EVP_DigestFinal. Fix it by
|
||||||
* Fix it by reinitializing ctx.
|
* reinitializing ctx.
|
||||||
*/
|
*/
|
||||||
EVP_DigestInit(ctx, md);
|
EVP_DigestInit(ctx, md);
|
||||||
}
|
}
|
||||||
|
@ -246,7 +244,9 @@ typedef struct
|
||||||
} des;
|
} des;
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
DES_key_schedule k1, k2, k3;
|
DES_key_schedule k1,
|
||||||
|
k2,
|
||||||
|
k3;
|
||||||
} des3;
|
} des3;
|
||||||
CAST_KEY cast_key;
|
CAST_KEY cast_key;
|
||||||
AES_KEY aes_key;
|
AES_KEY aes_key;
|
||||||
|
@ -825,7 +825,8 @@ static int openssl_random_init = 0;
|
||||||
* OpenSSL random should re-feeded occasionally. From /dev/urandom
|
* OpenSSL random should re-feeded occasionally. From /dev/urandom
|
||||||
* preferably.
|
* preferably.
|
||||||
*/
|
*/
|
||||||
static void init_openssl_rand(void)
|
static void
|
||||||
|
init_openssl_rand(void)
|
||||||
{
|
{
|
||||||
if (RAND_get_rand_method() == NULL)
|
if (RAND_get_rand_method() == NULL)
|
||||||
RAND_set_rand_method(RAND_SSLeay());
|
RAND_set_rand_method(RAND_SSLeay());
|
||||||
|
@ -871,4 +872,3 @@ px_add_entropy(const uint8 *data, unsigned count)
|
||||||
RAND_add(data, count, 0);
|
RAND_add(data, count, 0);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.19 2005/09/24 19:14:04 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgcrypto.c,v 1.20 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-armor.c,v 1.2 2005/07/11 15:07:59 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-armor.c,v 1.3 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -242,11 +242,13 @@ static const uint8 *
|
||||||
find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
|
find_str(const uint8 *data, const uint8 *data_end, const char *str, int strlen)
|
||||||
{
|
{
|
||||||
const uint8 *p = data;
|
const uint8 *p = data;
|
||||||
|
|
||||||
if (!strlen)
|
if (!strlen)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (data_end - data < strlen)
|
if (data_end - data < strlen)
|
||||||
return NULL;
|
return NULL;
|
||||||
while (p < data_end) {
|
while (p < data_end)
|
||||||
|
{
|
||||||
p = memchr(p, str[0], data_end - p);
|
p = memchr(p, str[0], data_end - p);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -313,7 +315,8 @@ pgp_armor_decode(const uint8 *src, unsigned len, uint8 *dst)
|
||||||
const uint8 *p = src;
|
const uint8 *p = src;
|
||||||
const uint8 *data_end = src + len;
|
const uint8 *data_end = src + len;
|
||||||
long crc;
|
long crc;
|
||||||
const uint8 *base64_start, *armor_end;
|
const uint8 *base64_start,
|
||||||
|
*armor_end;
|
||||||
const uint8 *base64_end = NULL;
|
const uint8 *base64_end = NULL;
|
||||||
uint8 buf[4];
|
uint8 buf[4];
|
||||||
int hlen;
|
int hlen;
|
||||||
|
@ -378,4 +381,3 @@ pgp_armor_dec_len(unsigned len)
|
||||||
{
|
{
|
||||||
return b64_dec_len(len);
|
return b64_dec_len(len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-cfb.c,v 1.2 2005/07/11 15:07:59 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-cfb.c,v 1.3 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -96,6 +96,7 @@ static int
|
||||||
mix_encrypt_normal(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
mix_encrypt_normal(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = ctx->pos; i < ctx->pos + len; i++)
|
for (i = ctx->pos; i < ctx->pos + len; i++)
|
||||||
*dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
|
*dst++ = ctx->encbuf[i] = ctx->fre[i] ^ (*data++);
|
||||||
ctx->pos += len;
|
ctx->pos += len;
|
||||||
|
@ -106,6 +107,7 @@ static int
|
||||||
mix_decrypt_normal(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
mix_decrypt_normal(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = ctx->pos; i < ctx->pos + len; i++)
|
for (i = ctx->pos; i < ctx->pos + len; i++)
|
||||||
{
|
{
|
||||||
ctx->encbuf[i] = *data++;
|
ctx->encbuf[i] = *data++;
|
||||||
|
@ -124,7 +126,9 @@ mix_decrypt_normal(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
static int
|
static int
|
||||||
mix_encrypt_resync(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
mix_encrypt_resync(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
int i,n;
|
int i,
|
||||||
|
n;
|
||||||
|
|
||||||
/* block #2 is 2 bytes long */
|
/* block #2 is 2 bytes long */
|
||||||
if (ctx->block_no == 2)
|
if (ctx->block_no == 2)
|
||||||
{
|
{
|
||||||
|
@ -154,7 +158,9 @@ mix_encrypt_resync(PGP_CFB *ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
static int
|
static int
|
||||||
mix_decrypt_resync(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
mix_decrypt_resync(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
int i,n;
|
int i,
|
||||||
|
n;
|
||||||
|
|
||||||
/* block #2 is 2 bytes long */
|
/* block #2 is 2 bytes long */
|
||||||
if (ctx->block_no == 2)
|
if (ctx->block_no == 2)
|
||||||
{
|
{
|
||||||
|
@ -246,6 +252,7 @@ int
|
||||||
pgp_cfb_encrypt(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
pgp_cfb_encrypt(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
mix_data_t mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
|
mix_data_t mix = ctx->resync ? mix_encrypt_resync : mix_encrypt_normal;
|
||||||
|
|
||||||
return cfb_process(ctx, data, len, dst, mix);
|
return cfb_process(ctx, data, len, dst, mix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -253,6 +260,6 @@ int
|
||||||
pgp_cfb_decrypt(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
pgp_cfb_decrypt(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst)
|
||||||
{
|
{
|
||||||
mix_data_t mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
|
mix_data_t mix = ctx->resync ? mix_decrypt_resync : mix_decrypt_normal;
|
||||||
|
|
||||||
return cfb_process(ctx, data, len, dst, mix);
|
return cfb_process(ctx, data, len, dst, mix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-compress.c,v 1.4 2005/07/18 17:09:01 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-compress.c,v 1.5 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -236,7 +236,8 @@ decompress_init(void **priv_p, void *arg, PullFilter *src)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decompress_read(void *priv, PullFilter *src, int len,
|
static int
|
||||||
|
decompress_read(void *priv, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen)
|
uint8 **data_p, uint8 *buf, int buflen)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -257,8 +258,10 @@ restart:
|
||||||
if (dec->eof)
|
if (dec->eof)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (dec->stream.avail_in == 0) {
|
if (dec->stream.avail_in == 0)
|
||||||
|
{
|
||||||
uint8 *tmp;
|
uint8 *tmp;
|
||||||
|
|
||||||
res = pullf_read(src, 8192, &tmp);
|
res = pullf_read(src, 8192, &tmp);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
@ -271,9 +274,9 @@ restart:
|
||||||
dec->pos = dec->buf;
|
dec->pos = dec->buf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Z_SYNC_FLUSH is tell zlib to output as much as possible.
|
* Z_SYNC_FLUSH is tell zlib to output as much as possible. It should do
|
||||||
* It should do it anyway (Z_NO_FLUSH), but seems to reserve
|
* it anyway (Z_NO_FLUSH), but seems to reserve the right not to. So lets
|
||||||
* the right not to. So lets follow the API.
|
* follow the API.
|
||||||
*/
|
*/
|
||||||
flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
|
flush = dec->stream.avail_in ? Z_SYNC_FLUSH : Z_FINISH;
|
||||||
res = inflate(&dec->stream, flush);
|
res = inflate(&dec->stream, flush);
|
||||||
|
@ -289,9 +292,11 @@ restart:
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void decompress_free(void *priv)
|
static void
|
||||||
|
decompress_free(void *priv)
|
||||||
{
|
{
|
||||||
struct DecomprData *dec = priv;
|
struct DecomprData *dec = priv;
|
||||||
|
|
||||||
inflateEnd(&dec->stream);
|
inflateEnd(&dec->stream);
|
||||||
memset(dec, 0, sizeof(*dec));
|
memset(dec, 0, sizeof(*dec));
|
||||||
px_free(dec);
|
px_free(dec);
|
||||||
|
@ -307,7 +312,6 @@ pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
|
||||||
{
|
{
|
||||||
return pullf_create(res, &decompress_filter, ctx, src);
|
return pullf_create(res, &decompress_filter, ctx, src);
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* DISABLE_ZLIB */
|
#else /* DISABLE_ZLIB */
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -323,5 +327,3 @@ pgp_decompress_filter(PullFilter **res, PGP_Context *ctx, PullFilter *src)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-decrypt.c,v 1.5 2005/09/24 19:14:04 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-decrypt.c,v 1.6 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -165,12 +165,14 @@ pgp_parse_pkt_hdr(PullFilter * src, uint8 *tag, int *len_p, int allow_ctx)
|
||||||
/*
|
/*
|
||||||
* Packet reader
|
* Packet reader
|
||||||
*/
|
*/
|
||||||
struct PktData {
|
struct PktData
|
||||||
|
{
|
||||||
int type;
|
int type;
|
||||||
int len;
|
int len;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int pktreader_pull(void *priv, PullFilter *src, int len,
|
static int
|
||||||
|
pktreader_pull(void *priv, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen)
|
uint8 **data_p, uint8 *buf, int buflen)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -207,6 +209,7 @@ static void
|
||||||
pktreader_free(void *priv)
|
pktreader_free(void *priv)
|
||||||
{
|
{
|
||||||
struct PktData *pkt = priv;
|
struct PktData *pkt = priv;
|
||||||
|
|
||||||
memset(pkt, 0, sizeof(*pkt));
|
memset(pkt, 0, sizeof(*pkt));
|
||||||
px_free(pkt);
|
px_free(pkt);
|
||||||
}
|
}
|
||||||
|
@ -222,6 +225,7 @@ pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct PktData *pkt = px_alloc(sizeof(*pkt));
|
struct PktData *pkt = px_alloc(sizeof(*pkt));
|
||||||
|
|
||||||
pkt->type = pkttype;
|
pkt->type = pkttype;
|
||||||
pkt->len = len;
|
pkt->len = len;
|
||||||
res = pullf_create(pf_p, &pktreader_filter, pkt, src);
|
res = pullf_create(pf_p, &pktreader_filter, pkt, src);
|
||||||
|
@ -234,7 +238,8 @@ pgp_create_pkt_reader(PullFilter **pf_p, PullFilter *src, int len,
|
||||||
* Prefix check filter
|
* Prefix check filter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int prefix_init(void **priv_p, void *arg, PullFilter *src)
|
static int
|
||||||
|
prefix_init(void **priv_p, void *arg, PullFilter * src)
|
||||||
{
|
{
|
||||||
PGP_Context *ctx = arg;
|
PGP_Context *ctx = arg;
|
||||||
int len;
|
int len;
|
||||||
|
@ -259,20 +264,19 @@ static int prefix_init(void **priv_p, void *arg, PullFilter *src)
|
||||||
if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
|
if (buf[len - 2] != buf[len] || buf[len - 1] != buf[len + 1])
|
||||||
{
|
{
|
||||||
px_debug("prefix_init: corrupt prefix");
|
px_debug("prefix_init: corrupt prefix");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The original purpose of the 2-byte check was
|
* The original purpose of the 2-byte check was to show user a
|
||||||
* to show user a friendly "wrong key" message.
|
* friendly "wrong key" message. This made following possible:
|
||||||
* This made following possible:
|
|
||||||
*
|
*
|
||||||
* "An Attack on CFB Mode Encryption As Used By OpenPGP"
|
* "An Attack on CFB Mode Encryption As Used By OpenPGP" by Serge Mister
|
||||||
* by Serge Mister and Robert Zuccherato
|
* and Robert Zuccherato
|
||||||
*
|
*
|
||||||
* To avoid being 'oracle', we delay reporting, which
|
* To avoid being 'oracle', we delay reporting, which basically means we
|
||||||
* basically means we prefer to run into corrupt packet
|
* prefer to run into corrupt packet header.
|
||||||
* header.
|
|
||||||
*
|
*
|
||||||
* We _could_ throw PXE_PGP_CORRUPT_DATA here, but
|
* We _could_ throw PXE_PGP_CORRUPT_DATA here, but there is possibility
|
||||||
* there is possibility of attack via timing, so we don't.
|
* of attack via timing, so we don't.
|
||||||
*/
|
*/
|
||||||
ctx->corrupt_prefix = 1;
|
ctx->corrupt_prefix = 1;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +293,8 @@ static struct PullFilterOps prefix_filter = {
|
||||||
* Decrypt filter
|
* Decrypt filter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int decrypt_init(void **priv_p, void *arg, PullFilter *src)
|
static int
|
||||||
|
decrypt_init(void **priv_p, void *arg, PullFilter * src)
|
||||||
{
|
{
|
||||||
PGP_CFB *cfb = arg;
|
PGP_CFB *cfb = arg;
|
||||||
|
|
||||||
|
@ -299,7 +304,8 @@ static int decrypt_init(void **priv_p, void *arg, PullFilter *src)
|
||||||
return 4096;
|
return 4096;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int decrypt_read(void *priv, PullFilter *src, int len,
|
static int
|
||||||
|
decrypt_read(void *priv, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen)
|
uint8 **data_p, uint8 *buf, int buflen)
|
||||||
{
|
{
|
||||||
PGP_CFB *cfb = priv;
|
PGP_CFB *cfb = priv;
|
||||||
|
@ -307,7 +313,8 @@ static int decrypt_read(void *priv, PullFilter *src, int len,
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = pullf_read(src, len, &tmp);
|
res = pullf_read(src, len, &tmp);
|
||||||
if (res > 0) {
|
if (res > 0)
|
||||||
|
{
|
||||||
pgp_cfb_decrypt(cfb, tmp, res, buf);
|
pgp_cfb_decrypt(cfb, tmp, res, buf);
|
||||||
*data_p = buf;
|
*data_p = buf;
|
||||||
}
|
}
|
||||||
|
@ -323,23 +330,28 @@ struct PullFilterOps pgp_decrypt_filter = {
|
||||||
* MDC hasher filter
|
* MDC hasher filter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int mdc_init(void **priv_p, void *arg, PullFilter *src)
|
static int
|
||||||
|
mdc_init(void **priv_p, void *arg, PullFilter * src)
|
||||||
{
|
{
|
||||||
PGP_Context *ctx = arg;
|
PGP_Context *ctx = arg;
|
||||||
|
|
||||||
*priv_p = ctx;
|
*priv_p = ctx;
|
||||||
return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
|
return pgp_load_digest(PGP_DIGEST_SHA1, &ctx->mdc_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdc_free(void *priv)
|
static void
|
||||||
|
mdc_free(void *priv)
|
||||||
{
|
{
|
||||||
PGP_Context *ctx = priv;
|
PGP_Context *ctx = priv;
|
||||||
|
|
||||||
if (ctx->use_mdcbuf_filter)
|
if (ctx->use_mdcbuf_filter)
|
||||||
return;
|
return;
|
||||||
px_md_free(ctx->mdc_ctx);
|
px_md_free(ctx->mdc_ctx);
|
||||||
ctx->mdc_ctx = NULL;
|
ctx->mdc_ctx = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdc_finish(PGP_Context *ctx, PullFilter *src,
|
static int
|
||||||
|
mdc_finish(PGP_Context * ctx, PullFilter * src,
|
||||||
int len, uint8 **data_p)
|
int len, uint8 **data_p)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -394,7 +406,8 @@ static int mdc_finish(PGP_Context *ctx, PullFilter *src,
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdc_read(void *priv, PullFilter *src, int len,
|
static int
|
||||||
|
mdc_read(void *priv, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen)
|
uint8 **data_p, uint8 *buf, int buflen)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -434,7 +447,8 @@ static struct PullFilterOps mdc_filter = {
|
||||||
* packet, which is silly.
|
* packet, which is silly.
|
||||||
*/
|
*/
|
||||||
#define MDCBUF_LEN 8192
|
#define MDCBUF_LEN 8192
|
||||||
struct MDCBufData {
|
struct MDCBufData
|
||||||
|
{
|
||||||
PGP_Context *ctx;
|
PGP_Context *ctx;
|
||||||
int eof;
|
int eof;
|
||||||
int buflen;
|
int buflen;
|
||||||
|
@ -445,7 +459,8 @@ struct MDCBufData {
|
||||||
uint8 buf[MDCBUF_LEN];
|
uint8 buf[MDCBUF_LEN];
|
||||||
};
|
};
|
||||||
|
|
||||||
static int mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
|
static int
|
||||||
|
mdcbuf_init(void **priv_p, void *arg, PullFilter * src)
|
||||||
{
|
{
|
||||||
PGP_Context *ctx = arg;
|
PGP_Context *ctx = arg;
|
||||||
struct MDCBufData *st;
|
struct MDCBufData *st;
|
||||||
|
@ -462,7 +477,8 @@ static int mdcbuf_init(void **priv_p, void *arg, PullFilter *src)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdcbuf_finish(struct MDCBufData *st)
|
static int
|
||||||
|
mdcbuf_finish(struct MDCBufData * st)
|
||||||
{
|
{
|
||||||
uint8 hash[20];
|
uint8 hash[20];
|
||||||
int res;
|
int res;
|
||||||
|
@ -486,21 +502,25 @@ static int mdcbuf_finish(struct MDCBufData *st)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdcbuf_load_data(struct MDCBufData *st, uint8 *src, int len)
|
static void
|
||||||
|
mdcbuf_load_data(struct MDCBufData * st, uint8 *src, int len)
|
||||||
{
|
{
|
||||||
uint8 *dst = st->pos + st->avail;
|
uint8 *dst = st->pos + st->avail;
|
||||||
|
|
||||||
memcpy(dst, src, len);
|
memcpy(dst, src, len);
|
||||||
px_md_update(st->ctx->mdc_ctx, src, len);
|
px_md_update(st->ctx->mdc_ctx, src, len);
|
||||||
st->avail += len;
|
st->avail += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mdcbuf_load_mdc(struct MDCBufData *st, uint8 *src, int len)
|
static void
|
||||||
|
mdcbuf_load_mdc(struct MDCBufData * st, uint8 *src, int len)
|
||||||
{
|
{
|
||||||
memmove(st->mdc_buf + st->mdc_avail, src, len);
|
memmove(st->mdc_buf + st->mdc_avail, src, len);
|
||||||
st->mdc_avail += len;
|
st->mdc_avail += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdcbuf_refill(struct MDCBufData *st, PullFilter *src)
|
static int
|
||||||
|
mdcbuf_refill(struct MDCBufData * st, PullFilter * src)
|
||||||
{
|
{
|
||||||
uint8 *data;
|
uint8 *data;
|
||||||
int res;
|
int res;
|
||||||
|
@ -531,6 +551,7 @@ static int mdcbuf_refill(struct MDCBufData *st, PullFilter *src)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int canmove = st->mdc_avail + res - 22;
|
int canmove = st->mdc_avail + res - 22;
|
||||||
|
|
||||||
if (canmove > 0)
|
if (canmove > 0)
|
||||||
{
|
{
|
||||||
mdcbuf_load_data(st, st->mdc_buf, canmove);
|
mdcbuf_load_data(st, st->mdc_buf, canmove);
|
||||||
|
@ -542,7 +563,8 @@ static int mdcbuf_refill(struct MDCBufData *st, PullFilter *src)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mdcbuf_read(void *priv, PullFilter *src, int len,
|
static int
|
||||||
|
mdcbuf_read(void *priv, PullFilter * src, int len,
|
||||||
uint8 **data_p, uint8 *buf, int buflen)
|
uint8 **data_p, uint8 *buf, int buflen)
|
||||||
{
|
{
|
||||||
struct MDCBufData *st = priv;
|
struct MDCBufData *st = priv;
|
||||||
|
@ -568,6 +590,7 @@ static void
|
||||||
mdcbuf_free(void *priv)
|
mdcbuf_free(void *priv)
|
||||||
{
|
{
|
||||||
struct MDCBufData *st = priv;
|
struct MDCBufData *st = priv;
|
||||||
|
|
||||||
px_md_free(st->ctx->mdc_ctx);
|
px_md_free(st->ctx->mdc_ctx);
|
||||||
st->ctx->mdc_ctx = NULL;
|
st->ctx->mdc_ctx = NULL;
|
||||||
memset(st, 0, sizeof(*st));
|
memset(st, 0, sizeof(*st));
|
||||||
|
@ -603,7 +626,8 @@ decrypt_key(PGP_Context *ctx, const uint8 *src, int len)
|
||||||
ctx->sess_key_len = len;
|
ctx->sess_key_len = len;
|
||||||
ctx->cipher_algo = algo;
|
ctx->cipher_algo = algo;
|
||||||
|
|
||||||
if (pgp_get_cipher_key_size(algo) != len) {
|
if (pgp_get_cipher_key_size(algo) != len)
|
||||||
|
{
|
||||||
px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
|
px_debug("sesskey bad len: algo=%d, expected=%d, got=%d",
|
||||||
algo, pgp_get_cipher_key_size(algo), len);
|
algo, pgp_get_cipher_key_size(algo), len);
|
||||||
return PXE_PGP_CORRUPT_DATA;
|
return PXE_PGP_CORRUPT_DATA;
|
||||||
|
@ -693,12 +717,14 @@ copy_crlf(MBuf *dst, uint8 *data, int len, int *got_cr)
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
p = tmpbuf;
|
p = tmpbuf;
|
||||||
if (*got_cr) {
|
if (*got_cr)
|
||||||
|
{
|
||||||
if (*data != '\n')
|
if (*data != '\n')
|
||||||
*p++ = '\r';
|
*p++ = '\r';
|
||||||
*got_cr = 0;
|
*got_cr = 0;
|
||||||
}
|
}
|
||||||
while (data < data_end) {
|
while (data < data_end)
|
||||||
|
{
|
||||||
if (*data == '\r')
|
if (*data == '\r')
|
||||||
{
|
{
|
||||||
if (data + 1 < data_end)
|
if (data + 1 < data_end)
|
||||||
|
@ -779,7 +805,8 @@ parse_literal_data(PGP_Context * ctx, MBuf * dst, PullFilter * pkt)
|
||||||
ctx->unicode_mode = (type == 'u') ? 1 : 0;
|
ctx->unicode_mode = (type == 'u') ? 1 : 0;
|
||||||
|
|
||||||
/* read data */
|
/* read data */
|
||||||
while (1) {
|
while (1)
|
||||||
|
{
|
||||||
res = pullf_read(pkt, 32 * 1024, &buf);
|
res = pullf_read(pkt, 32 * 1024, &buf);
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -1038,6 +1065,7 @@ pgp_skip_packet(PullFilter *pkt)
|
||||||
{
|
{
|
||||||
int res = 1;
|
int res = 1;
|
||||||
uint8 *tmp;
|
uint8 *tmp;
|
||||||
|
|
||||||
while (res > 0)
|
while (res > 0)
|
||||||
res = pullf_read(pkt, 32 * 1024, &tmp);
|
res = pullf_read(pkt, 32 * 1024, &tmp);
|
||||||
return res < 0 ? res : 0;
|
return res < 0 ? res : 0;
|
||||||
|
@ -1051,6 +1079,7 @@ pgp_expect_packet_end(PullFilter *pkt)
|
||||||
{
|
{
|
||||||
int res = 1;
|
int res = 1;
|
||||||
uint8 *tmp;
|
uint8 *tmp;
|
||||||
|
|
||||||
while (res > 0)
|
while (res > 0)
|
||||||
{
|
{
|
||||||
res = pullf_read(pkt, 32 * 1024, &tmp);
|
res = pullf_read(pkt, 32 * 1024, &tmp);
|
||||||
|
@ -1076,7 +1105,8 @@ pgp_decrypt(PGP_Context * ctx, MBuf * msrc, MBuf * mdst)
|
||||||
|
|
||||||
res = pullf_create_mbuf_reader(&src, msrc);
|
res = pullf_create_mbuf_reader(&src, msrc);
|
||||||
|
|
||||||
while (res >= 0) {
|
while (res >= 0)
|
||||||
|
{
|
||||||
res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
|
res = pgp_parse_pkt_hdr(src, &tag, &len, NO_CTX_SIZE);
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -1086,7 +1116,8 @@ pgp_decrypt(PGP_Context * ctx, MBuf * msrc, MBuf * mdst)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
res = PXE_PGP_CORRUPT_DATA;
|
res = PXE_PGP_CORRUPT_DATA;
|
||||||
switch (tag) {
|
switch (tag)
|
||||||
|
{
|
||||||
case PGP_PKT_MARKER:
|
case PGP_PKT_MARKER:
|
||||||
res = pgp_skip_packet(pkt);
|
res = pgp_skip_packet(pkt);
|
||||||
break;
|
break;
|
||||||
|
@ -1097,10 +1128,11 @@ pgp_decrypt(PGP_Context * ctx, MBuf * msrc, MBuf * mdst)
|
||||||
break;
|
break;
|
||||||
case PGP_PKT_SYMENCRYPTED_SESSKEY:
|
case PGP_PKT_SYMENCRYPTED_SESSKEY:
|
||||||
if (got_key)
|
if (got_key)
|
||||||
/* Theoretically, there could be several keys,
|
|
||||||
* both public and symmetric, all of which
|
/*
|
||||||
* encrypt same session key. Decrypt should try
|
* Theoretically, there could be several keys, both public
|
||||||
* with each one, before failing.
|
* and symmetric, all of which encrypt same session key.
|
||||||
|
* Decrypt should try with each one, before failing.
|
||||||
*/
|
*/
|
||||||
px_debug("pgp_decrypt: using first of several keys");
|
px_debug("pgp_decrypt: using first of several keys");
|
||||||
else
|
else
|
||||||
|
@ -1154,4 +1186,3 @@ pgp_decrypt(PGP_Context * ctx, MBuf * msrc, MBuf * mdst)
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-encrypt.c,v 1.2 2005/07/11 15:07:59 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-encrypt.c,v 1.3 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -65,9 +65,11 @@ render_newlen(uint8 *h, int len)
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int write_tag_only(PushFilter *dst, int tag)
|
static int
|
||||||
|
write_tag_only(PushFilter * dst, int tag)
|
||||||
{
|
{
|
||||||
uint8 hdr = 0xC0 | tag;
|
uint8 hdr = 0xC0 | tag;
|
||||||
|
|
||||||
return pushf_write(dst, &hdr, 1);
|
return pushf_write(dst, &hdr, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,6 +168,7 @@ encrypt_init(PushFilter * next, void *init_arg, void **priv_p)
|
||||||
if (ctx->disable_mdc == 0)
|
if (ctx->disable_mdc == 0)
|
||||||
{
|
{
|
||||||
uint8 ver = 1;
|
uint8 ver = 1;
|
||||||
|
|
||||||
resync = 0;
|
resync = 0;
|
||||||
res = pushf_write(next, &ver, 1);
|
res = pushf_write(next, &ver, 1);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
|
@ -194,6 +197,7 @@ encrypt_process(PushFilter * next, void *priv, const uint8 *data, int len)
|
||||||
while (avail > 0)
|
while (avail > 0)
|
||||||
{
|
{
|
||||||
int tmplen = avail > ENCBUF ? ENCBUF : avail;
|
int tmplen = avail > ENCBUF ? ENCBUF : avail;
|
||||||
|
|
||||||
res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
|
res = pgp_cfb_encrypt(st->ciph, data, tmplen, st->buf);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
@ -303,9 +307,11 @@ static const PushFilterOps pkt_stream_filter = {
|
||||||
pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
|
pkt_stream_init, pkt_stream_process, pkt_stream_flush, pkt_stream_free
|
||||||
};
|
};
|
||||||
|
|
||||||
int pgp_create_pkt_writer(PushFilter *dst, int tag, PushFilter **res_p)
|
int
|
||||||
|
pgp_create_pkt_writer(PushFilter * dst, int tag, PushFilter ** res_p)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = write_tag_only(dst, tag);
|
res = write_tag_only(dst, tag);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
@ -321,10 +327,12 @@ static int
|
||||||
crlf_process(PushFilter * dst, void *priv, const uint8 *data, int len)
|
crlf_process(PushFilter * dst, void *priv, const uint8 *data, int len)
|
||||||
{
|
{
|
||||||
const uint8 *data_end = data + len;
|
const uint8 *data_end = data + len;
|
||||||
const uint8 * p2, * p1 = data;
|
const uint8 *p2,
|
||||||
|
*p1 = data;
|
||||||
int line_len;
|
int line_len;
|
||||||
static const uint8 crlf[] = {'\r', '\n'};
|
static const uint8 crlf[] = {'\r', '\n'};
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
while (p1 < data_end)
|
while (p1 < data_end)
|
||||||
{
|
{
|
||||||
p2 = memchr(p1, '\n', data_end - p1);
|
p2 = memchr(p1, '\n', data_end - p1);
|
||||||
|
@ -382,8 +390,8 @@ init_litdata_packet(PushFilter **pf_res, PGP_Context *ctx, PushFilter *dst)
|
||||||
type = 'b';
|
type = 'b';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Store the creation time into packet.
|
* Store the creation time into packet. The goal is to have as few known
|
||||||
* The goal is to have as few known bytes as possible.
|
* bytes as possible.
|
||||||
*/
|
*/
|
||||||
t = (uint32) time(NULL);
|
t = (uint32) time(NULL);
|
||||||
|
|
||||||
|
@ -571,6 +579,7 @@ static int
|
||||||
init_sess_key(PGP_Context * ctx)
|
init_sess_key(PGP_Context * ctx)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
if (ctx->use_sess_key || ctx->pub_key)
|
if (ctx->use_sess_key || ctx->pub_key)
|
||||||
{
|
{
|
||||||
ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
|
ctx->sess_key_len = pgp_get_cipher_key_size(ctx->cipher_algo);
|
||||||
|
@ -596,7 +605,8 @@ pgp_encrypt(PGP_Context * ctx, MBuf * src, MBuf * dst)
|
||||||
int res;
|
int res;
|
||||||
int len;
|
int len;
|
||||||
uint8 *buf;
|
uint8 *buf;
|
||||||
PushFilter *pf, *pf_tmp;
|
PushFilter *pf,
|
||||||
|
*pf_tmp;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* do we have any key
|
* do we have any key
|
||||||
|
@ -696,4 +706,3 @@ out:
|
||||||
pushf_free_all(pf);
|
pushf_free_all(pf);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-info.c,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-info.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -34,7 +34,8 @@
|
||||||
#include "mbuf.h"
|
#include "mbuf.h"
|
||||||
#include "pgp.h"
|
#include "pgp.h"
|
||||||
|
|
||||||
static int read_pubkey_keyid(PullFilter *pkt, uint8 *keyid_buf)
|
static int
|
||||||
|
read_pubkey_keyid(PullFilter * pkt, uint8 *keyid_buf)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PGP_PubKey *pk = NULL;
|
PGP_PubKey *pk = NULL;
|
||||||
|
@ -66,7 +67,8 @@ err:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_pubenc_keyid(PullFilter *pkt, uint8 *keyid_buf)
|
static int
|
||||||
|
read_pubenc_keyid(PullFilter * pkt, uint8 *keyid_buf)
|
||||||
{
|
{
|
||||||
uint8 ver;
|
uint8 ver;
|
||||||
int res;
|
int res;
|
||||||
|
@ -89,7 +91,9 @@ print_key(uint8 *keyid, char *dst)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned c;
|
unsigned c;
|
||||||
for (i = 0; i < 8; i++) {
|
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
c = keyid[i];
|
c = keyid[i];
|
||||||
*dst++ = hextbl[(c >> 4) & 0x0F];
|
*dst++ = hextbl[(c >> 4) & 0x0F];
|
||||||
*dst++ = hextbl[c & 0x0F];
|
*dst++ = hextbl[c & 0x0F];
|
||||||
|
@ -112,7 +116,9 @@ pgp_get_keyid(MBuf *pgp_data, char *dst)
|
||||||
PullFilter *pkt = NULL;
|
PullFilter *pkt = NULL;
|
||||||
int len;
|
int len;
|
||||||
uint8 tag;
|
uint8 tag;
|
||||||
int got_pub_key=0, got_symenc_key=0, got_pubenc_key=0;
|
int got_pub_key = 0,
|
||||||
|
got_symenc_key = 0,
|
||||||
|
got_pubenc_key = 0;
|
||||||
int got_data = 0;
|
int got_data = 0;
|
||||||
uint8 keyid_buf[8];
|
uint8 keyid_buf[8];
|
||||||
int got_main_key = 0;
|
int got_main_key = 0;
|
||||||
|
@ -122,7 +128,8 @@ pgp_get_keyid(MBuf *pgp_data, char *dst)
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
while (1) {
|
while (1)
|
||||||
|
{
|
||||||
res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
|
res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -226,4 +233,3 @@ pgp_get_keyid(MBuf *pgp_data, char *dst)
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-internal.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -48,14 +48,14 @@ pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
|
||||||
return PXE_PGP_NO_BIGNUM;
|
return PXE_PGP_NO_BIGNUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c)
|
int
|
||||||
|
pgp_rsa_encrypt(PGP_PubKey * pk, PGP_MPI * m, PGP_MPI ** c)
|
||||||
{
|
{
|
||||||
return PXE_PGP_NO_BIGNUM;
|
return PXE_PGP_NO_BIGNUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *c, PGP_MPI **m)
|
int
|
||||||
|
pgp_rsa_decrypt(PGP_PubKey * pk, PGP_MPI * c, PGP_MPI ** m)
|
||||||
{
|
{
|
||||||
return PXE_PGP_NO_BIGNUM;
|
return PXE_PGP_NO_BIGNUM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-openssl.c,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi-openssl.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -40,6 +40,7 @@ static BIGNUM *
|
||||||
mpi_to_bn(PGP_MPI * n)
|
mpi_to_bn(PGP_MPI * n)
|
||||||
{
|
{
|
||||||
BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL);
|
BIGNUM *bn = BN_bin2bn(n->data, n->bytes, NULL);
|
||||||
|
|
||||||
if (!bn)
|
if (!bn)
|
||||||
return NULL;
|
return NULL;
|
||||||
if (BN_num_bits(bn) != n->bits)
|
if (BN_num_bits(bn) != n->bits)
|
||||||
|
@ -124,8 +125,7 @@ pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* c1 = g^k
|
* c1 = g^k c2 = m * y^k
|
||||||
* c2 = m * y^k
|
|
||||||
*/
|
*/
|
||||||
if (!BN_mod_exp(c1, g, k, p, tmp))
|
if (!BN_mod_exp(c1, g, k, p, tmp))
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -140,15 +140,24 @@ pgp_elgamal_encrypt(PGP_PubKey *pk, PGP_MPI *_m,
|
||||||
if (*c1_p && *c2_p)
|
if (*c1_p && *c2_p)
|
||||||
res = 0;
|
res = 0;
|
||||||
err:
|
err:
|
||||||
if (tmp) BN_CTX_free(tmp);
|
if (tmp)
|
||||||
if (c2) BN_clear_free(c2);
|
BN_CTX_free(tmp);
|
||||||
if (c1) BN_clear_free(c1);
|
if (c2)
|
||||||
if (yk) BN_clear_free(yk);
|
BN_clear_free(c2);
|
||||||
if (k) BN_clear_free(k);
|
if (c1)
|
||||||
if (y) BN_clear_free(y);
|
BN_clear_free(c1);
|
||||||
if (g) BN_clear_free(g);
|
if (yk)
|
||||||
if (p) BN_clear_free(p);
|
BN_clear_free(yk);
|
||||||
if (m) BN_clear_free(m);
|
if (k)
|
||||||
|
BN_clear_free(k);
|
||||||
|
if (y)
|
||||||
|
BN_clear_free(y);
|
||||||
|
if (g)
|
||||||
|
BN_clear_free(g);
|
||||||
|
if (p)
|
||||||
|
BN_clear_free(p);
|
||||||
|
if (m)
|
||||||
|
BN_clear_free(m);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,14 +193,22 @@ pgp_elgamal_decrypt(PGP_PubKey *pk, PGP_MPI *_c1, PGP_MPI *_c2,
|
||||||
if (*msg_p)
|
if (*msg_p)
|
||||||
res = 0;
|
res = 0;
|
||||||
err:
|
err:
|
||||||
if (tmp) BN_CTX_free(tmp);
|
if (tmp)
|
||||||
if (m) BN_clear_free(m);
|
BN_CTX_free(tmp);
|
||||||
if (div) BN_clear_free(div);
|
if (m)
|
||||||
if (c1x) BN_clear_free(c1x);
|
BN_clear_free(m);
|
||||||
if (x) BN_clear_free(x);
|
if (div)
|
||||||
if (p) BN_clear_free(p);
|
BN_clear_free(div);
|
||||||
if (c2) BN_clear_free(c2);
|
if (c1x)
|
||||||
if (c1) BN_clear_free(c1);
|
BN_clear_free(c1x);
|
||||||
|
if (x)
|
||||||
|
BN_clear_free(x);
|
||||||
|
if (p)
|
||||||
|
BN_clear_free(p);
|
||||||
|
if (c2)
|
||||||
|
BN_clear_free(c2);
|
||||||
|
if (c1)
|
||||||
|
BN_clear_free(c1);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,11 +235,16 @@ pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *_m, PGP_MPI **c_p)
|
||||||
if (*c_p)
|
if (*c_p)
|
||||||
res = 0;
|
res = 0;
|
||||||
err:
|
err:
|
||||||
if (tmp) BN_CTX_free(tmp);
|
if (tmp)
|
||||||
if (c) BN_clear_free(c);
|
BN_CTX_free(tmp);
|
||||||
if (n) BN_clear_free(n);
|
if (c)
|
||||||
if (e) BN_clear_free(e);
|
BN_clear_free(c);
|
||||||
if (m) BN_clear_free(m);
|
if (n)
|
||||||
|
BN_clear_free(n);
|
||||||
|
if (e)
|
||||||
|
BN_clear_free(e);
|
||||||
|
if (m)
|
||||||
|
BN_clear_free(m);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,11 +271,15 @@ pgp_rsa_decrypt(PGP_PubKey *pk, PGP_MPI *_c, PGP_MPI **m_p)
|
||||||
if (*m_p)
|
if (*m_p)
|
||||||
res = 0;
|
res = 0;
|
||||||
err:
|
err:
|
||||||
if (tmp) BN_CTX_free(tmp);
|
if (tmp)
|
||||||
if (m) BN_clear_free(m);
|
BN_CTX_free(tmp);
|
||||||
if (n) BN_clear_free(n);
|
if (m)
|
||||||
if (d) BN_clear_free(d);
|
BN_clear_free(m);
|
||||||
if (c) BN_clear_free(c);
|
if (n)
|
||||||
|
BN_clear_free(n);
|
||||||
|
if (d)
|
||||||
|
BN_clear_free(d);
|
||||||
|
if (c)
|
||||||
|
BN_clear_free(c);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi.c,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-mpi.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -34,10 +34,12 @@
|
||||||
#include "mbuf.h"
|
#include "mbuf.h"
|
||||||
#include "pgp.h"
|
#include "pgp.h"
|
||||||
|
|
||||||
int pgp_mpi_alloc(int bits, PGP_MPI **mpi)
|
int
|
||||||
|
pgp_mpi_alloc(int bits, PGP_MPI ** mpi)
|
||||||
{
|
{
|
||||||
PGP_MPI *n;
|
PGP_MPI *n;
|
||||||
int len = (bits + 7) / 8;
|
int len = (bits + 7) / 8;
|
||||||
|
|
||||||
if (bits < 0 || bits > 0xFFFF)
|
if (bits < 0 || bits > 0xFFFF)
|
||||||
{
|
{
|
||||||
px_debug("pgp_mpi_alloc: unreasonable request: bits=%d", bits);
|
px_debug("pgp_mpi_alloc: unreasonable request: bits=%d", bits);
|
||||||
|
@ -51,7 +53,8 @@ int pgp_mpi_alloc(int bits, PGP_MPI **mpi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi)
|
int
|
||||||
|
pgp_mpi_create(uint8 *data, int bits, PGP_MPI ** mpi)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PGP_MPI *n;
|
PGP_MPI *n;
|
||||||
|
@ -64,7 +67,8 @@ int pgp_mpi_create(uint8 *data, int bits, PGP_MPI **mpi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_mpi_free(PGP_MPI *mpi)
|
int
|
||||||
|
pgp_mpi_free(PGP_MPI * mpi)
|
||||||
{
|
{
|
||||||
if (mpi == NULL)
|
if (mpi == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -73,7 +77,8 @@ int pgp_mpi_free(PGP_MPI *mpi)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_mpi_read(PullFilter *src, PGP_MPI **mpi)
|
int
|
||||||
|
pgp_mpi_read(PullFilter * src, PGP_MPI ** mpi)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
uint8 hdr[2];
|
uint8 hdr[2];
|
||||||
|
@ -97,7 +102,8 @@ int pgp_mpi_read(PullFilter *src, PGP_MPI **mpi)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_mpi_write(PushFilter *dst, PGP_MPI *n)
|
int
|
||||||
|
pgp_mpi_write(PushFilter * dst, PGP_MPI * n)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
uint8 buf[2];
|
uint8 buf[2];
|
||||||
|
@ -110,7 +116,8 @@ int pgp_mpi_write(PushFilter *dst, PGP_MPI *n)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_mpi_hash(PX_MD *md, PGP_MPI *n)
|
int
|
||||||
|
pgp_mpi_hash(PX_MD * md, PGP_MPI * n)
|
||||||
{
|
{
|
||||||
uint8 buf[2];
|
uint8 buf[2];
|
||||||
|
|
||||||
|
@ -122,7 +129,8 @@ int pgp_mpi_hash(PX_MD *md, PGP_MPI *n)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned pgp_mpi_cksum(unsigned cksum, PGP_MPI *n)
|
unsigned
|
||||||
|
pgp_mpi_cksum(unsigned cksum, PGP_MPI * n)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
@ -133,4 +141,3 @@ unsigned pgp_mpi_cksum(unsigned cksum, PGP_MPI *n)
|
||||||
|
|
||||||
return cksum & 0xFFFF;
|
return cksum & 0xFFFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pgsql.c,v 1.5 2005/09/24 19:14:04 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pgsql.c,v 1.6 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -89,7 +89,8 @@ PG_FUNCTION_INFO_V1(pg_dearmor);
|
||||||
/*
|
/*
|
||||||
* Mix a block of data into RNG.
|
* Mix a block of data into RNG.
|
||||||
*/
|
*/
|
||||||
static void add_block_entropy(PX_MD *md, text *data)
|
static void
|
||||||
|
add_block_entropy(PX_MD * md, text *data)
|
||||||
{
|
{
|
||||||
uint8 sha1[20];
|
uint8 sha1[20];
|
||||||
|
|
||||||
|
@ -106,7 +107,8 @@ static void add_block_entropy(PX_MD *md, text *data)
|
||||||
* Mix user data into RNG. It is for user own interests to have
|
* Mix user data into RNG. It is for user own interests to have
|
||||||
* RNG state shuffled.
|
* RNG state shuffled.
|
||||||
*/
|
*/
|
||||||
static void add_entropy(text *data1, text *data2, text *data3)
|
static void
|
||||||
|
add_entropy(text *data1, text *data2, text *data3)
|
||||||
{
|
{
|
||||||
PX_MD *md;
|
PX_MD *md;
|
||||||
uint8 rnd[3];
|
uint8 rnd[3];
|
||||||
|
@ -123,8 +125,8 @@ static void add_entropy(text *data1, text *data2, text *data3)
|
||||||
/*
|
/*
|
||||||
* Try to make the feeding unpredictable.
|
* Try to make the feeding unpredictable.
|
||||||
*
|
*
|
||||||
* Prefer data over keys, as it's rather likely
|
* Prefer data over keys, as it's rather likely that key is same in several
|
||||||
* that key is same in several calls.
|
* calls.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* chance: 7/8 */
|
/* chance: 7/8 */
|
||||||
|
@ -146,7 +148,8 @@ static void add_entropy(text *data1, text *data2, text *data3)
|
||||||
/*
|
/*
|
||||||
* returns src in case of no conversion or error
|
* returns src in case of no conversion or error
|
||||||
*/
|
*/
|
||||||
static text *convert_charset(text *src, int cset_from, int cset_to)
|
static text *
|
||||||
|
convert_charset(text *src, int cset_from, int cset_to)
|
||||||
{
|
{
|
||||||
int src_len = VARSIZE(src) - VARHDRSZ;
|
int src_len = VARSIZE(src) - VARHDRSZ;
|
||||||
int dst_len;
|
int dst_len;
|
||||||
|
@ -166,12 +169,14 @@ static text *convert_charset(text *src, int cset_from, int cset_to)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static text *convert_from_utf8(text *src)
|
static text *
|
||||||
|
convert_from_utf8(text *src)
|
||||||
{
|
{
|
||||||
return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
|
return convert_charset(src, PG_UTF8, GetDatabaseEncoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
static text *convert_to_utf8(text *src)
|
static text *
|
||||||
|
convert_to_utf8(text *src)
|
||||||
{
|
{
|
||||||
return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
|
return convert_charset(src, GetDatabaseEncoding(), PG_UTF8);
|
||||||
}
|
}
|
||||||
|
@ -186,7 +191,8 @@ clear_and_pfree(text *p)
|
||||||
/*
|
/*
|
||||||
* expect-* arguments storage
|
* expect-* arguments storage
|
||||||
*/
|
*/
|
||||||
struct debug_expect {
|
struct debug_expect
|
||||||
|
{
|
||||||
int debug;
|
int debug;
|
||||||
int expect;
|
int expect;
|
||||||
int cipher_algo;
|
int cipher_algo;
|
||||||
|
@ -199,7 +205,8 @@ struct debug_expect {
|
||||||
int unicode_mode;
|
int unicode_mode;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void fill_expect(struct debug_expect *ex, int text_mode)
|
static void
|
||||||
|
fill_expect(struct debug_expect * ex, int text_mode)
|
||||||
{
|
{
|
||||||
ex->debug = 0;
|
ex->debug = 0;
|
||||||
ex->expect = 0;
|
ex->expect = 0;
|
||||||
|
@ -222,7 +229,8 @@ static void fill_expect(struct debug_expect *ex, int text_mode)
|
||||||
if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
|
if (ex->arg >= 0 && ex->arg != ctx->arg) EX_MSG(arg); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
static void check_expect(PGP_Context *ctx, struct debug_expect *ex)
|
static void
|
||||||
|
check_expect(PGP_Context * ctx, struct debug_expect * ex)
|
||||||
{
|
{
|
||||||
EX_CHECK(cipher_algo);
|
EX_CHECK(cipher_algo);
|
||||||
EX_CHECK(s2k_mode);
|
EX_CHECK(s2k_mode);
|
||||||
|
@ -235,15 +243,18 @@ static void check_expect(PGP_Context *ctx, struct debug_expect *ex)
|
||||||
EX_CHECK(unicode_mode);
|
EX_CHECK(unicode_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void show_debug(const char *msg)
|
static void
|
||||||
|
show_debug(const char *msg)
|
||||||
{
|
{
|
||||||
ereport(NOTICE, (errmsg("dbg: %s", msg)));
|
ereport(NOTICE, (errmsg("dbg: %s", msg)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int set_arg(PGP_Context *ctx, char *key, char*val,
|
static int
|
||||||
|
set_arg(PGP_Context * ctx, char *key, char *val,
|
||||||
struct debug_expect * ex)
|
struct debug_expect * ex)
|
||||||
{
|
{
|
||||||
int res = 0;
|
int res = 0;
|
||||||
|
|
||||||
if (strcmp(key, "cipher-algo") == 0)
|
if (strcmp(key, "cipher-algo") == 0)
|
||||||
res = pgp_set_cipher_algo(ctx, val);
|
res = pgp_set_cipher_algo(ctx, val);
|
||||||
else if (strcmp(key, "disable-mdc") == 0)
|
else if (strcmp(key, "disable-mdc") == 0)
|
||||||
|
@ -318,7 +329,8 @@ static int set_arg(PGP_Context *ctx, char *key, char*val,
|
||||||
* Put word info into res_p, res_len.
|
* Put word info into res_p, res_len.
|
||||||
* Returns ptr to next word.
|
* Returns ptr to next word.
|
||||||
*/
|
*/
|
||||||
static char *getword(char *p, char **res_p, int *res_len)
|
static char *
|
||||||
|
getword(char *p, char **res_p, int *res_len)
|
||||||
{
|
{
|
||||||
/* whitespace at start */
|
/* whitespace at start */
|
||||||
while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
|
while (*p && (*p == ' ' || *p == '\t' || *p == '\n'))
|
||||||
|
@ -346,11 +358,15 @@ static char *getword(char *p, char **res_p, int *res_len)
|
||||||
/*
|
/*
|
||||||
* Convert to lowercase asciiz string.
|
* Convert to lowercase asciiz string.
|
||||||
*/
|
*/
|
||||||
static char *downcase_convert(const uint8 *s, int len)
|
static char *
|
||||||
|
downcase_convert(const uint8 *s, int len)
|
||||||
{
|
{
|
||||||
int c, i;
|
int c,
|
||||||
|
i;
|
||||||
char *res = palloc(len + 1);
|
char *res = palloc(len + 1);
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
|
for (i = 0; i < len; i++)
|
||||||
|
{
|
||||||
c = s[i];
|
c = s[i];
|
||||||
if (c >= 'A' && c <= 'Z')
|
if (c >= 'A' && c <= 'Z')
|
||||||
c += 'a' - 'A';
|
c += 'a' - 'A';
|
||||||
|
@ -360,12 +376,15 @@ static char *downcase_convert(const uint8 *s, int len)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int parse_args(PGP_Context *ctx, uint8 *args, int arg_len,
|
static int
|
||||||
|
parse_args(PGP_Context * ctx, uint8 *args, int arg_len,
|
||||||
struct debug_expect * ex)
|
struct debug_expect * ex)
|
||||||
{
|
{
|
||||||
char *str = downcase_convert(args, arg_len);
|
char *str = downcase_convert(args, arg_len);
|
||||||
char *key, *val;
|
char *key,
|
||||||
int key_len, val_len;
|
*val;
|
||||||
|
int key_len,
|
||||||
|
val_len;
|
||||||
int res = 0;
|
int res = 0;
|
||||||
char *p = str;
|
char *p = str;
|
||||||
|
|
||||||
|
@ -431,7 +450,8 @@ static bytea *
|
||||||
encrypt_internal(int is_pubenc, int is_text,
|
encrypt_internal(int is_pubenc, int is_text,
|
||||||
text *data, text *key, text *args)
|
text *data, text *key, text *args)
|
||||||
{
|
{
|
||||||
MBuf *src, *dst;
|
MBuf *src,
|
||||||
|
*dst;
|
||||||
uint8 tmp[VARHDRSZ];
|
uint8 tmp[VARHDRSZ];
|
||||||
uint8 *restmp;
|
uint8 *restmp;
|
||||||
bytea *res;
|
bytea *res;
|
||||||
|
@ -471,6 +491,7 @@ encrypt_internal(int is_pubenc, int is_text,
|
||||||
if (is_pubenc)
|
if (is_pubenc)
|
||||||
{
|
{
|
||||||
MBuf *kbuf = create_mbuf_from_vardata(key);
|
MBuf *kbuf = create_mbuf_from_vardata(key);
|
||||||
|
|
||||||
err = pgp_set_pubkey(ctx, kbuf,
|
err = pgp_set_pubkey(ctx, kbuf,
|
||||||
NULL, 0, 0);
|
NULL, 0, 0);
|
||||||
mbuf_free(kbuf);
|
mbuf_free(kbuf);
|
||||||
|
@ -523,7 +544,8 @@ decrypt_internal(int is_pubenc, int need_text, text *data,
|
||||||
text *key, text *keypsw, text *args)
|
text *key, text *keypsw, text *args)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
MBuf *src = NULL, *dst = NULL;
|
MBuf *src = NULL,
|
||||||
|
*dst = NULL;
|
||||||
uint8 tmp[VARHDRSZ];
|
uint8 tmp[VARHDRSZ];
|
||||||
uint8 *restmp;
|
uint8 *restmp;
|
||||||
bytea *res;
|
bytea *res;
|
||||||
|
@ -552,6 +574,7 @@ decrypt_internal(int is_pubenc, int need_text, text *data,
|
||||||
uint8 *psw = NULL;
|
uint8 *psw = NULL;
|
||||||
int psw_len = 0;
|
int psw_len = 0;
|
||||||
MBuf *kbuf;
|
MBuf *kbuf;
|
||||||
|
|
||||||
if (keypsw)
|
if (keypsw)
|
||||||
{
|
{
|
||||||
psw = (uint8 *) VARDATA(keypsw);
|
psw = (uint8 *) VARDATA(keypsw);
|
||||||
|
@ -609,6 +632,7 @@ out:
|
||||||
if (need_text && got_unicode)
|
if (need_text && got_unicode)
|
||||||
{
|
{
|
||||||
text *utf = convert_from_utf8(res);
|
text *utf = convert_from_utf8(res);
|
||||||
|
|
||||||
if (utf != res)
|
if (utf != res)
|
||||||
{
|
{
|
||||||
clear_and_pfree(res);
|
clear_and_pfree(res);
|
||||||
|
@ -927,4 +951,3 @@ pgp_key_id_w(PG_FUNCTION_ARGS)
|
||||||
PG_FREE_IF_COPY(data, 0);
|
PG_FREE_IF_COPY(data, 0);
|
||||||
PG_RETURN_TEXT_P(res);
|
PG_RETURN_TEXT_P(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubdec.c,v 1.4 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubdec.c,v 1.5 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -52,7 +52,8 @@ check_eme_pkcs1_v15(uint8 *data, int len)
|
||||||
if (*p++ != 2)
|
if (*p++ != 2)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
while (p < data_end && *p) {
|
while (p < data_end && *p)
|
||||||
|
{
|
||||||
p++;
|
p++;
|
||||||
rnd++;
|
rnd++;
|
||||||
}
|
}
|
||||||
|
@ -74,7 +75,8 @@ static int
|
||||||
control_cksum(uint8 *msg, int msglen)
|
control_cksum(uint8 *msg, int msglen)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
unsigned my_cksum, got_cksum;
|
unsigned my_cksum,
|
||||||
|
got_cksum;
|
||||||
|
|
||||||
if (msglen < 3)
|
if (msglen < 3)
|
||||||
return PXE_PGP_WRONG_KEY;
|
return PXE_PGP_WRONG_KEY;
|
||||||
|
@ -84,7 +86,8 @@ control_cksum(uint8 *msg, int msglen)
|
||||||
my_cksum += msg[i];
|
my_cksum += msg[i];
|
||||||
my_cksum &= 0xFFFF;
|
my_cksum &= 0xFFFF;
|
||||||
got_cksum = ((unsigned) (msg[msglen - 2]) << 8) + msg[msglen - 1];
|
got_cksum = ((unsigned) (msg[msglen - 2]) << 8) + msg[msglen - 1];
|
||||||
if (my_cksum != got_cksum) {
|
if (my_cksum != got_cksum)
|
||||||
|
{
|
||||||
px_debug("pubenc cksum failed");
|
px_debug("pubenc cksum failed");
|
||||||
return PXE_PGP_WRONG_KEY;
|
return PXE_PGP_WRONG_KEY;
|
||||||
}
|
}
|
||||||
|
@ -157,13 +160,15 @@ pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
|
||||||
PGP_MPI *m;
|
PGP_MPI *m;
|
||||||
|
|
||||||
pk = ctx->pub_key;
|
pk = ctx->pub_key;
|
||||||
if (pk == NULL) {
|
if (pk == NULL)
|
||||||
|
{
|
||||||
px_debug("no pubkey?");
|
px_debug("no pubkey?");
|
||||||
return PXE_BUG;
|
return PXE_BUG;
|
||||||
}
|
}
|
||||||
|
|
||||||
GETBYTE(pkt, ver);
|
GETBYTE(pkt, ver);
|
||||||
if (ver != 3) {
|
if (ver != 3)
|
||||||
|
{
|
||||||
px_debug("unknown pubenc_sesskey pkt ver=%d", ver);
|
px_debug("unknown pubenc_sesskey pkt ver=%d", ver);
|
||||||
return PXE_PGP_CORRUPT_DATA;
|
return PXE_PGP_CORRUPT_DATA;
|
||||||
}
|
}
|
||||||
|
@ -204,7 +209,8 @@ pgp_parse_pubenc_sesskey(PGP_Context *ctx, PullFilter *pkt)
|
||||||
* extract message
|
* extract message
|
||||||
*/
|
*/
|
||||||
msg = check_eme_pkcs1_v15(m->data, m->bytes);
|
msg = check_eme_pkcs1_v15(m->data, m->bytes);
|
||||||
if (msg == NULL) {
|
if (msg == NULL)
|
||||||
|
{
|
||||||
px_debug("check_eme_pkcs1_v15 failed");
|
px_debug("check_eme_pkcs1_v15 failed");
|
||||||
res = PXE_PGP_WRONG_KEY;
|
res = PXE_PGP_WRONG_KEY;
|
||||||
goto out;
|
goto out;
|
||||||
|
@ -228,5 +234,3 @@ out:
|
||||||
return res;
|
return res;
|
||||||
return pgp_expect_packet_end(pkt);
|
return pgp_expect_packet_end(pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubenc.c,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubenc.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -41,7 +41,8 @@ static int
|
||||||
pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
|
pad_eme_pkcs1_v15(uint8 *data, int data_len, int res_len, uint8 **res_p)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
uint8 *buf, *p;
|
uint8 *buf,
|
||||||
|
*p;
|
||||||
int pad_len = res_len - 2 - data_len;
|
int pad_len = res_len - 2 - data_len;
|
||||||
|
|
||||||
if (pad_len < 8)
|
if (pad_len < 8)
|
||||||
|
@ -88,7 +89,8 @@ static int
|
||||||
create_secmsg(PGP_Context * ctx, PGP_MPI ** msg_p, int full_bytes)
|
create_secmsg(PGP_Context * ctx, PGP_MPI ** msg_p, int full_bytes)
|
||||||
{
|
{
|
||||||
uint8 *secmsg;
|
uint8 *secmsg;
|
||||||
int res, i;
|
int res,
|
||||||
|
i;
|
||||||
unsigned cksum = 0;
|
unsigned cksum = 0;
|
||||||
int klen = ctx->sess_key_len;
|
int klen = ctx->sess_key_len;
|
||||||
uint8 *padded = NULL;
|
uint8 *padded = NULL;
|
||||||
|
@ -115,6 +117,7 @@ create_secmsg(PGP_Context *ctx, PGP_MPI **msg_p, int full_bytes)
|
||||||
{
|
{
|
||||||
/* first byte will be 0x02 */
|
/* first byte will be 0x02 */
|
||||||
int full_bits = full_bytes * 8 - 6;
|
int full_bits = full_bytes * 8 - 6;
|
||||||
|
|
||||||
res = pgp_mpi_create(padded, full_bits, &m);
|
res = pgp_mpi_create(padded, full_bits, &m);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,7 +139,9 @@ static int
|
||||||
encrypt_and_write_elgamal(PGP_Context * ctx, PGP_PubKey * pk, PushFilter * pkt)
|
encrypt_and_write_elgamal(PGP_Context * ctx, PGP_PubKey * pk, PushFilter * pkt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PGP_MPI *m = NULL, *c1 = NULL, *c2 = NULL;
|
PGP_MPI *m = NULL,
|
||||||
|
*c1 = NULL,
|
||||||
|
*c2 = NULL;
|
||||||
|
|
||||||
/* create padded msg */
|
/* create padded msg */
|
||||||
res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1);
|
res = create_secmsg(ctx, &m, pk->pub.elg.p->bytes - 1);
|
||||||
|
@ -165,7 +170,8 @@ static int
|
||||||
encrypt_and_write_rsa(PGP_Context * ctx, PGP_PubKey * pk, PushFilter * pkt)
|
encrypt_and_write_rsa(PGP_Context * ctx, PGP_PubKey * pk, PushFilter * pkt)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PGP_MPI *m = NULL, *c = NULL;
|
PGP_MPI *m = NULL,
|
||||||
|
*c = NULL;
|
||||||
|
|
||||||
/* create padded msg */
|
/* create padded msg */
|
||||||
res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1);
|
res = create_secmsg(ctx, &m, pk->pub.rsa.n->bytes - 1);
|
||||||
|
@ -186,7 +192,8 @@ err:
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
|
int
|
||||||
|
pgp_write_pubenc_sesskey(PGP_Context * ctx, PushFilter * dst)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PGP_PubKey *pk = ctx->pub_key;
|
PGP_PubKey *pk = ctx->pub_key;
|
||||||
|
@ -194,7 +201,8 @@ int pgp_write_pubenc_sesskey(PGP_Context *ctx, PushFilter *dst)
|
||||||
PushFilter *pkt = NULL;
|
PushFilter *pkt = NULL;
|
||||||
uint8 algo = pk->algo;
|
uint8 algo = pk->algo;
|
||||||
|
|
||||||
if (pk == NULL) {
|
if (pk == NULL)
|
||||||
|
{
|
||||||
px_debug("no pubkey?\n");
|
px_debug("no pubkey?\n");
|
||||||
return PXE_BUG;
|
return PXE_BUG;
|
||||||
}
|
}
|
||||||
|
@ -238,5 +246,3 @@ err:
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubkey.c,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-pubkey.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
|
@ -34,16 +34,19 @@
|
||||||
#include "mbuf.h"
|
#include "mbuf.h"
|
||||||
#include "pgp.h"
|
#include "pgp.h"
|
||||||
|
|
||||||
int pgp_key_alloc(PGP_PubKey **pk_p)
|
int
|
||||||
|
pgp_key_alloc(PGP_PubKey ** pk_p)
|
||||||
{
|
{
|
||||||
PGP_PubKey *pk;
|
PGP_PubKey *pk;
|
||||||
|
|
||||||
pk = px_alloc(sizeof(*pk));
|
pk = px_alloc(sizeof(*pk));
|
||||||
memset(pk, 0, sizeof(*pk));
|
memset(pk, 0, sizeof(*pk));
|
||||||
*pk_p = pk;
|
*pk_p = pk;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pgp_key_free(PGP_PubKey *pk)
|
void
|
||||||
|
pgp_key_free(PGP_PubKey * pk)
|
||||||
{
|
{
|
||||||
if (pk == NULL)
|
if (pk == NULL)
|
||||||
return;
|
return;
|
||||||
|
@ -152,7 +155,8 @@ calc_key_id(PGP_PubKey *pk)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p)
|
int
|
||||||
|
_pgp_read_public_key(PullFilter * pkt, PGP_PubKey ** pk_p)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PGP_PubKey *pk;
|
PGP_PubKey *pk;
|
||||||
|
@ -163,7 +167,8 @@ int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p)
|
||||||
|
|
||||||
/* get version */
|
/* get version */
|
||||||
GETBYTE(pkt, pk->ver);
|
GETBYTE(pkt, pk->ver);
|
||||||
if (pk->ver != 4) {
|
if (pk->ver != 4)
|
||||||
|
{
|
||||||
res = PXE_PGP_NOT_V4_KEYPKT;
|
res = PXE_PGP_NOT_V4_KEYPKT;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
@ -176,16 +181,21 @@ int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p)
|
||||||
/* pubkey algorithm */
|
/* pubkey algorithm */
|
||||||
GETBYTE(pkt, pk->algo);
|
GETBYTE(pkt, pk->algo);
|
||||||
|
|
||||||
switch (pk->algo) {
|
switch (pk->algo)
|
||||||
|
{
|
||||||
case PGP_PUB_DSA_SIGN:
|
case PGP_PUB_DSA_SIGN:
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.dsa.p);
|
res = pgp_mpi_read(pkt, &pk->pub.dsa.p);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.dsa.q);
|
res = pgp_mpi_read(pkt, &pk->pub.dsa.q);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.dsa.g);
|
res = pgp_mpi_read(pkt, &pk->pub.dsa.g);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.dsa.y);
|
res = pgp_mpi_read(pkt, &pk->pub.dsa.y);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
res = calc_key_id(pk);
|
res = calc_key_id(pk);
|
||||||
break;
|
break;
|
||||||
|
@ -194,9 +204,11 @@ int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p)
|
||||||
case PGP_PUB_RSA_ENCRYPT:
|
case PGP_PUB_RSA_ENCRYPT:
|
||||||
case PGP_PUB_RSA_ENCRYPT_SIGN:
|
case PGP_PUB_RSA_ENCRYPT_SIGN:
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.rsa.n);
|
res = pgp_mpi_read(pkt, &pk->pub.rsa.n);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.rsa.e);
|
res = pgp_mpi_read(pkt, &pk->pub.rsa.e);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
res = calc_key_id(pk);
|
res = calc_key_id(pk);
|
||||||
|
|
||||||
|
@ -206,11 +218,14 @@ int _pgp_read_public_key(PullFilter *pkt, PGP_PubKey **pk_p)
|
||||||
|
|
||||||
case PGP_PUB_ELG_ENCRYPT:
|
case PGP_PUB_ELG_ENCRYPT:
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.elg.p);
|
res = pgp_mpi_read(pkt, &pk->pub.elg.p);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.elg.g);
|
res = pgp_mpi_read(pkt, &pk->pub.elg.g);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->pub.elg.y);
|
res = pgp_mpi_read(pkt, &pk->pub.elg.y);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
res = calc_key_id(pk);
|
res = calc_key_id(pk);
|
||||||
|
|
||||||
|
@ -285,7 +300,8 @@ static int
|
||||||
check_key_cksum(PullFilter * src, PGP_PubKey * pk)
|
check_key_cksum(PullFilter * src, PGP_PubKey * pk)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
unsigned got_cksum, my_cksum = 0;
|
unsigned got_cksum,
|
||||||
|
my_cksum = 0;
|
||||||
uint8 buf[2];
|
uint8 buf[2];
|
||||||
|
|
||||||
res = pullf_read_fixed(src, 2, buf);
|
res = pullf_read_fixed(src, 2, buf);
|
||||||
|
@ -318,7 +334,8 @@ check_key_cksum(PullFilter *src, PGP_PubKey *pk)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
|
static int
|
||||||
|
process_secret_key(PullFilter * pkt, PGP_PubKey ** pk_p,
|
||||||
const uint8 *key, int key_len)
|
const uint8 *key, int key_len)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
|
@ -326,7 +343,8 @@ static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
|
||||||
int cipher_algo;
|
int cipher_algo;
|
||||||
int bs;
|
int bs;
|
||||||
uint8 iv[512];
|
uint8 iv[512];
|
||||||
PullFilter *pf_decrypt = NULL, *pf_key;
|
PullFilter *pf_decrypt = NULL,
|
||||||
|
*pf_key;
|
||||||
PGP_CFB *cfb = NULL;
|
PGP_CFB *cfb = NULL;
|
||||||
PGP_S2K s2k;
|
PGP_S2K s2k;
|
||||||
PGP_PubKey *pk;
|
PGP_PubKey *pk;
|
||||||
|
@ -340,7 +358,8 @@ static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
|
||||||
* is secret key encrypted?
|
* is secret key encrypted?
|
||||||
*/
|
*/
|
||||||
GETBYTE(pkt, hide_type);
|
GETBYTE(pkt, hide_type);
|
||||||
if (hide_type == HIDE_SHA1 || hide_type == HIDE_CKSUM) {
|
if (hide_type == HIDE_SHA1 || hide_type == HIDE_CKSUM)
|
||||||
|
{
|
||||||
if (key == NULL)
|
if (key == NULL)
|
||||||
return PXE_PGP_NEED_SECRET_PSW;
|
return PXE_PGP_NEED_SECRET_PSW;
|
||||||
GETBYTE(pkt, cipher_algo);
|
GETBYTE(pkt, cipher_algo);
|
||||||
|
@ -353,13 +372,15 @@ static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
bs = pgp_get_cipher_block_size(cipher_algo);
|
bs = pgp_get_cipher_block_size(cipher_algo);
|
||||||
if (bs == 0) {
|
if (bs == 0)
|
||||||
|
{
|
||||||
px_debug("unknown cipher algo=%d", cipher_algo);
|
px_debug("unknown cipher algo=%d", cipher_algo);
|
||||||
return PXE_PGP_UNSUPPORTED_CIPHER;
|
return PXE_PGP_UNSUPPORTED_CIPHER;
|
||||||
}
|
}
|
||||||
res = pullf_read_fixed(pkt, bs, iv);
|
res = pullf_read_fixed(pkt, bs, iv);
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* create decrypt filter
|
* create decrypt filter
|
||||||
*/
|
*/
|
||||||
|
@ -370,26 +391,35 @@ static int process_secret_key(PullFilter *pkt, PGP_PubKey **pk_p,
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
pf_key = pf_decrypt;
|
pf_key = pf_decrypt;
|
||||||
} else if (hide_type == HIDE_CLEAR) {
|
}
|
||||||
|
else if (hide_type == HIDE_CLEAR)
|
||||||
|
{
|
||||||
pf_key = pkt;
|
pf_key = pkt;
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
px_debug("unknown hide type");
|
px_debug("unknown hide type");
|
||||||
return PXE_PGP_KEYPKT_CORRUPT;
|
return PXE_PGP_KEYPKT_CORRUPT;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* read secret key */
|
/* read secret key */
|
||||||
switch (pk->algo) {
|
switch (pk->algo)
|
||||||
|
{
|
||||||
case PGP_PUB_RSA_SIGN:
|
case PGP_PUB_RSA_SIGN:
|
||||||
case PGP_PUB_RSA_ENCRYPT:
|
case PGP_PUB_RSA_ENCRYPT:
|
||||||
case PGP_PUB_RSA_ENCRYPT_SIGN:
|
case PGP_PUB_RSA_ENCRYPT_SIGN:
|
||||||
res = pgp_mpi_read(pkt, &pk->sec.rsa.d);
|
res = pgp_mpi_read(pkt, &pk->sec.rsa.d);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->sec.rsa.p);
|
res = pgp_mpi_read(pkt, &pk->sec.rsa.p);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->sec.rsa.q);
|
res = pgp_mpi_read(pkt, &pk->sec.rsa.q);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
res = pgp_mpi_read(pkt, &pk->sec.rsa.u);
|
res = pgp_mpi_read(pkt, &pk->sec.rsa.u);
|
||||||
if (res < 0) break;
|
if (res < 0)
|
||||||
|
break;
|
||||||
break;
|
break;
|
||||||
case PGP_PUB_ELG_ENCRYPT:
|
case PGP_PUB_ELG_ENCRYPT:
|
||||||
res = pgp_mpi_read(pf_key, &pk->sec.elg.x);
|
res = pgp_mpi_read(pf_key, &pk->sec.elg.x);
|
||||||
|
@ -442,7 +472,8 @@ internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
|
||||||
*
|
*
|
||||||
* Error out on anything fancy.
|
* Error out on anything fancy.
|
||||||
*/
|
*/
|
||||||
while (1) {
|
while (1)
|
||||||
|
{
|
||||||
res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
|
res = pgp_parse_pkt_hdr(src, &tag, &len, 0);
|
||||||
if (res <= 0)
|
if (res <= 0)
|
||||||
break;
|
break;
|
||||||
|
@ -450,7 +481,8 @@ internal_read_key(PullFilter *src, PGP_PubKey **pk_p,
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (tag) {
|
switch (tag)
|
||||||
|
{
|
||||||
case PGP_PKT_PUBLIC_KEY:
|
case PGP_PKT_PUBLIC_KEY:
|
||||||
case PGP_PKT_SECRET_KEY:
|
case PGP_PKT_SECRET_KEY:
|
||||||
if (got_main_key)
|
if (got_main_key)
|
||||||
|
@ -550,4 +582,3 @@ pgp_set_pubkey(PGP_Context *ctx, MBuf *keypkt,
|
||||||
|
|
||||||
return res < 0 ? res : 0;
|
return res < 0 ? res : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-s2k.c,v 1.3 2005/07/18 17:12:54 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp-s2k.c,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -221,7 +221,8 @@ pgp_s2k_fill(PGP_S2K *s2k, int mode,int digest_algo)
|
||||||
s2k->mode = mode;
|
s2k->mode = mode;
|
||||||
s2k->digest_algo = digest_algo;
|
s2k->digest_algo = digest_algo;
|
||||||
|
|
||||||
switch (s2k->mode) {
|
switch (s2k->mode)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -249,7 +250,8 @@ pgp_s2k_read(PullFilter *src, PGP_S2K *s2k)
|
||||||
|
|
||||||
GETBYTE(src, s2k->mode);
|
GETBYTE(src, s2k->mode);
|
||||||
GETBYTE(src, s2k->digest_algo);
|
GETBYTE(src, s2k->digest_algo);
|
||||||
switch (s2k->mode) {
|
switch (s2k->mode)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -267,7 +269,8 @@ pgp_s2k_read(PullFilter *src, PGP_S2K *s2k)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
|
int
|
||||||
|
pgp_s2k_process(PGP_S2K * s2k, int cipher, const uint8 *key, int key_len)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
PX_MD *md;
|
PX_MD *md;
|
||||||
|
@ -280,7 +283,8 @@ int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
|
||||||
if (res < 0)
|
if (res < 0)
|
||||||
return res;
|
return res;
|
||||||
|
|
||||||
switch (s2k->mode) {
|
switch (s2k->mode)
|
||||||
|
{
|
||||||
case 0:
|
case 0:
|
||||||
res = calc_s2k_simple(s2k, md, key, key_len);
|
res = calc_s2k_simple(s2k, md, key, key_len);
|
||||||
break;
|
break;
|
||||||
|
@ -296,4 +300,3 @@ int pgp_s2k_process(PGP_S2K *s2k, int cipher, const uint8 *key, int key_len)
|
||||||
px_md_free(md);
|
px_md_free(md);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp.c,v 1.2 2005/07/11 15:07:59 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp.c,v 1.3 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -94,6 +94,7 @@ static const struct cipher_info *
|
||||||
get_cipher_info(int code)
|
get_cipher_info(int code)
|
||||||
{
|
{
|
||||||
const struct cipher_info *i;
|
const struct cipher_info *i;
|
||||||
|
|
||||||
for (i = cipher_list; i->name; i++)
|
for (i = cipher_list; i->name; i++)
|
||||||
if (i->code == code)
|
if (i->code == code)
|
||||||
return i;
|
return i;
|
||||||
|
@ -104,6 +105,7 @@ int
|
||||||
pgp_get_digest_code(const char *name)
|
pgp_get_digest_code(const char *name)
|
||||||
{
|
{
|
||||||
const struct digest_info *i;
|
const struct digest_info *i;
|
||||||
|
|
||||||
for (i = digest_list; i->name; i++)
|
for (i = digest_list; i->name; i++)
|
||||||
if (pg_strcasecmp(i->name, name) == 0)
|
if (pg_strcasecmp(i->name, name) == 0)
|
||||||
return i->code;
|
return i->code;
|
||||||
|
@ -114,6 +116,7 @@ int
|
||||||
pgp_get_cipher_code(const char *name)
|
pgp_get_cipher_code(const char *name)
|
||||||
{
|
{
|
||||||
const struct cipher_info *i;
|
const struct cipher_info *i;
|
||||||
|
|
||||||
for (i = cipher_list; i->name; i++)
|
for (i = cipher_list; i->name; i++)
|
||||||
if (pg_strcasecmp(i->name, name) == 0)
|
if (pg_strcasecmp(i->name, name) == 0)
|
||||||
return i->code;
|
return i->code;
|
||||||
|
@ -124,6 +127,7 @@ const char *
|
||||||
pgp_get_digest_name(int code)
|
pgp_get_digest_name(int code)
|
||||||
{
|
{
|
||||||
const struct digest_info *i;
|
const struct digest_info *i;
|
||||||
|
|
||||||
for (i = digest_list; i->name; i++)
|
for (i = digest_list; i->name; i++)
|
||||||
if (i->code == code)
|
if (i->code == code)
|
||||||
return i->name;
|
return i->name;
|
||||||
|
@ -134,6 +138,7 @@ const char *
|
||||||
pgp_get_cipher_name(int code)
|
pgp_get_cipher_name(int code)
|
||||||
{
|
{
|
||||||
const struct cipher_info *i = get_cipher_info(code);
|
const struct cipher_info *i = get_cipher_info(code);
|
||||||
|
|
||||||
if (i != NULL)
|
if (i != NULL)
|
||||||
return i->name;
|
return i->name;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -143,6 +148,7 @@ int
|
||||||
pgp_get_cipher_key_size(int code)
|
pgp_get_cipher_key_size(int code)
|
||||||
{
|
{
|
||||||
const struct cipher_info *i = get_cipher_info(code);
|
const struct cipher_info *i = get_cipher_info(code);
|
||||||
|
|
||||||
if (i != NULL)
|
if (i != NULL)
|
||||||
return i->key_len;
|
return i->key_len;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -152,6 +158,7 @@ int
|
||||||
pgp_get_cipher_block_size(int code)
|
pgp_get_cipher_block_size(int code)
|
||||||
{
|
{
|
||||||
const struct cipher_info *i = get_cipher_info(code);
|
const struct cipher_info *i = get_cipher_info(code);
|
||||||
|
|
||||||
if (i != NULL)
|
if (i != NULL)
|
||||||
return i->block_len;
|
return i->block_len;
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -300,6 +307,7 @@ int
|
||||||
pgp_set_cipher_algo(PGP_Context * ctx, const char *name)
|
pgp_set_cipher_algo(PGP_Context * ctx, const char *name)
|
||||||
{
|
{
|
||||||
int code = pgp_get_cipher_code(name);
|
int code = pgp_get_cipher_code(name);
|
||||||
|
|
||||||
if (code < 0)
|
if (code < 0)
|
||||||
return code;
|
return code;
|
||||||
ctx->cipher_algo = code;
|
ctx->cipher_algo = code;
|
||||||
|
@ -310,6 +318,7 @@ int
|
||||||
pgp_set_s2k_cipher_algo(PGP_Context * ctx, const char *name)
|
pgp_set_s2k_cipher_algo(PGP_Context * ctx, const char *name)
|
||||||
{
|
{
|
||||||
int code = pgp_get_cipher_code(name);
|
int code = pgp_get_cipher_code(name);
|
||||||
|
|
||||||
if (code < 0)
|
if (code < 0)
|
||||||
return code;
|
return code;
|
||||||
ctx->s2k_cipher_algo = code;
|
ctx->s2k_cipher_algo = code;
|
||||||
|
@ -320,6 +329,7 @@ int
|
||||||
pgp_set_s2k_digest_algo(PGP_Context * ctx, const char *name)
|
pgp_set_s2k_digest_algo(PGP_Context * ctx, const char *name)
|
||||||
{
|
{
|
||||||
int code = pgp_get_digest_code(name);
|
int code = pgp_get_digest_code(name);
|
||||||
|
|
||||||
if (code < 0)
|
if (code < 0)
|
||||||
return code;
|
return code;
|
||||||
ctx->s2k_digest_algo = code;
|
ctx->s2k_digest_algo = code;
|
||||||
|
@ -348,4 +358,3 @@ pgp_set_symkey(PGP_Context *ctx, const uint8 *key, int len)
|
||||||
ctx->sym_key_len = len;
|
ctx->sym_key_len = len;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp.h,v 1.3 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/pgp.h,v 1.4 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum
|
enum
|
||||||
|
@ -114,7 +114,8 @@ typedef struct PGP_PubKey PGP_PubKey;
|
||||||
typedef struct PGP_Context PGP_Context;
|
typedef struct PGP_Context PGP_Context;
|
||||||
typedef struct PGP_S2K PGP_S2K;
|
typedef struct PGP_S2K PGP_S2K;
|
||||||
|
|
||||||
struct PGP_S2K {
|
struct PGP_S2K
|
||||||
|
{
|
||||||
uint8 mode;
|
uint8 mode;
|
||||||
uint8 digest_algo;
|
uint8 digest_algo;
|
||||||
uint8 salt[8];
|
uint8 salt[8];
|
||||||
|
@ -163,29 +164,35 @@ struct PGP_Context
|
||||||
unsigned sess_key_len;
|
unsigned sess_key_len;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PGP_MPI {
|
struct PGP_MPI
|
||||||
|
{
|
||||||
uint8 *data;
|
uint8 *data;
|
||||||
int bits;
|
int bits;
|
||||||
int bytes;
|
int bytes;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct PGP_PubKey {
|
struct PGP_PubKey
|
||||||
|
{
|
||||||
uint8 ver;
|
uint8 ver;
|
||||||
uint8 time[4];
|
uint8 time[4];
|
||||||
uint8 algo;
|
uint8 algo;
|
||||||
|
|
||||||
/* public part */
|
/* public part */
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
PGP_MPI *p;
|
PGP_MPI *p;
|
||||||
PGP_MPI *g;
|
PGP_MPI *g;
|
||||||
PGP_MPI *y;
|
PGP_MPI *y;
|
||||||
} elg;
|
} elg;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
PGP_MPI *n;
|
PGP_MPI *n;
|
||||||
PGP_MPI *e;
|
PGP_MPI *e;
|
||||||
} rsa;
|
} rsa;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
PGP_MPI *p;
|
PGP_MPI *p;
|
||||||
PGP_MPI *q;
|
PGP_MPI *q;
|
||||||
PGP_MPI *g;
|
PGP_MPI *g;
|
||||||
|
@ -194,17 +201,21 @@ struct PGP_PubKey {
|
||||||
} pub;
|
} pub;
|
||||||
|
|
||||||
/* secret part */
|
/* secret part */
|
||||||
union {
|
union
|
||||||
struct {
|
{
|
||||||
|
struct
|
||||||
|
{
|
||||||
PGP_MPI *x;
|
PGP_MPI *x;
|
||||||
} elg;
|
} elg;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
PGP_MPI *d;
|
PGP_MPI *d;
|
||||||
PGP_MPI *p;
|
PGP_MPI *p;
|
||||||
PGP_MPI *q;
|
PGP_MPI *q;
|
||||||
PGP_MPI *u;
|
PGP_MPI *u;
|
||||||
} rsa;
|
} rsa;
|
||||||
struct {
|
struct
|
||||||
|
{
|
||||||
PGP_MPI *x;
|
PGP_MPI *x;
|
||||||
} dsa;
|
} dsa;
|
||||||
} sec;
|
} sec;
|
||||||
|
@ -254,7 +265,8 @@ int pgp_s2k_read(PullFilter *src, PGP_S2K *s2k);
|
||||||
int pgp_s2k_process(PGP_S2K * s2k, int cipher, const uint8 *key, int klen);
|
int pgp_s2k_process(PGP_S2K * s2k, int cipher, const uint8 *key, int klen);
|
||||||
|
|
||||||
typedef struct PGP_CFB PGP_CFB;
|
typedef struct PGP_CFB PGP_CFB;
|
||||||
int pgp_cfb_create(PGP_CFB **ctx_p, int algo,
|
int
|
||||||
|
pgp_cfb_create(PGP_CFB ** ctx_p, int algo,
|
||||||
const uint8 *key, int key_len, int recync, uint8 *iv);
|
const uint8 *key, int key_len, int recync, uint8 *iv);
|
||||||
void pgp_cfb_free(PGP_CFB * ctx);
|
void pgp_cfb_free(PGP_CFB * ctx);
|
||||||
int pgp_cfb_encrypt(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst);
|
int pgp_cfb_encrypt(PGP_CFB * ctx, const uint8 *data, int len, uint8 *dst);
|
||||||
|
@ -300,4 +312,3 @@ int pgp_rsa_encrypt(PGP_PubKey *pk, PGP_MPI *m, PGP_MPI **c);
|
||||||
int pgp_rsa_decrypt(PGP_PubKey * pk, PGP_MPI * c, PGP_MPI ** m);
|
int pgp_rsa_decrypt(PGP_PubKey * pk, PGP_MPI * c, PGP_MPI ** m);
|
||||||
|
|
||||||
extern struct PullFilterOps pgp_decrypt_filter;
|
extern struct PullFilterOps pgp_decrypt_filter;
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/px-crypt.c,v 1.14 2005/09/24 19:14:04 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/px-crypt.c,v 1.15 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -164,4 +164,3 @@ px_gen_salt(const char *salt_type, char *buf, int rounds)
|
||||||
|
|
||||||
return strlen(p);
|
return strlen(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/px-crypt.h,v 1.8 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/px-crypt.h,v 1.9 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef _PX_CRYPT_H
|
#ifndef _PX_CRYPT_H
|
||||||
|
|
|
@ -26,14 +26,15 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/px.c,v 1.14 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/px.c,v 1.15 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
|
||||||
#include "px.h"
|
#include "px.h"
|
||||||
|
|
||||||
struct error_desc {
|
struct error_desc
|
||||||
|
{
|
||||||
int err;
|
int err;
|
||||||
const char *desc;
|
const char *desc;
|
||||||
};
|
};
|
||||||
|
@ -91,9 +92,11 @@ static const struct error_desc px_err_list[] = {
|
||||||
{0, NULL},
|
{0, NULL},
|
||||||
};
|
};
|
||||||
|
|
||||||
const char *px_strerror(int err)
|
const char *
|
||||||
|
px_strerror(int err)
|
||||||
{
|
{
|
||||||
const struct error_desc *e;
|
const struct error_desc *e;
|
||||||
|
|
||||||
for (e = px_err_list; e->desc; e++)
|
for (e = px_err_list; e->desc; e++)
|
||||||
if (e->err == err)
|
if (e->err == err)
|
||||||
return e->desc;
|
return e->desc;
|
||||||
|
@ -115,17 +118,22 @@ px_resolve_alias(const PX_Alias * list, const char *name)
|
||||||
|
|
||||||
static void (*debug_handler) (const char *) = NULL;
|
static void (*debug_handler) (const char *) = NULL;
|
||||||
|
|
||||||
void px_set_debug_handler(void (*handler)(const char *))
|
void
|
||||||
|
px_set_debug_handler(void (*handler) (const char *))
|
||||||
{
|
{
|
||||||
debug_handler = handler;
|
debug_handler = handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
void px_debug(const char *fmt, ...)
|
void
|
||||||
|
px_debug(const char *fmt,...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
va_start(ap, fmt);
|
va_start(ap, fmt);
|
||||||
if (debug_handler) {
|
if (debug_handler)
|
||||||
|
{
|
||||||
char buf[512];
|
char buf[512];
|
||||||
|
|
||||||
vsnprintf(buf, sizeof(buf), fmt, ap);
|
vsnprintf(buf, sizeof(buf), fmt, ap);
|
||||||
debug_handler(buf);
|
debug_handler(buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/px.h,v 1.15 2005/08/13 02:06:20 momjian Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/px.h,v 1.16 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef __PX_H
|
#ifndef __PX_H
|
||||||
|
@ -208,6 +208,7 @@ const char *px_strerror(int err);
|
||||||
const char *px_resolve_alias(const PX_Alias * aliases, const char *name);
|
const char *px_resolve_alias(const PX_Alias * aliases, const char *name);
|
||||||
|
|
||||||
void px_set_debug_handler(void (*handler) (const char *));
|
void px_set_debug_handler(void (*handler) (const char *));
|
||||||
|
|
||||||
#ifdef PX_DEBUG
|
#ifdef PX_DEBUG
|
||||||
void px_debug(const char *fmt,...);
|
void px_debug(const char *fmt,...);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/random.c,v 1.15 2005/07/18 17:09:01 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/random.c,v 1.16 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -95,7 +95,6 @@ try_dev_random(uint8 *dst)
|
||||||
dst += res;
|
dst += res;
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -114,7 +113,8 @@ try_dev_random(uint8 *dst)
|
||||||
*
|
*
|
||||||
* try to use Microsoft crypto API
|
* try to use Microsoft crypto API
|
||||||
*/
|
*/
|
||||||
static uint8 * try_win32_genrand(uint8 *dst)
|
static uint8 *
|
||||||
|
try_win32_genrand(uint8 *dst)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
HCRYPTPROV h = 0;
|
HCRYPTPROV h = 0;
|
||||||
|
@ -135,7 +135,8 @@ static uint8 * try_win32_genrand(uint8 *dst)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8 * try_win32_perfc(uint8 *dst)
|
static uint8 *
|
||||||
|
try_win32_perfc(uint8 *dst)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
LARGE_INTEGER time;
|
LARGE_INTEGER time;
|
||||||
|
@ -147,7 +148,6 @@ static uint8 * try_win32_perfc(uint8 *dst)
|
||||||
memcpy(dst, &time, sizeof(time));
|
memcpy(dst, &time, sizeof(time));
|
||||||
return dst + sizeof(time);
|
return dst + sizeof(time);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WIN32 */
|
#endif /* WIN32 */
|
||||||
|
|
||||||
|
|
||||||
|
@ -197,7 +197,8 @@ try_unix_std(uint8 *dst)
|
||||||
|
|
||||||
/* let's be desperate */
|
/* let's be desperate */
|
||||||
res = px_find_digest("sha1", &md);
|
res = px_find_digest("sha1", &md);
|
||||||
if (res >= 0) {
|
if (res >= 0)
|
||||||
|
{
|
||||||
uint8 *ptr;
|
uint8 *ptr;
|
||||||
uint8 stack[8192];
|
uint8 stack[8192];
|
||||||
int alloc = 32 * 1024;
|
int alloc = 32 * 1024;
|
||||||
|
@ -215,7 +216,6 @@ try_unix_std(uint8 *dst)
|
||||||
|
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -223,9 +223,11 @@ try_unix_std(uint8 *dst)
|
||||||
*
|
*
|
||||||
* dst should have room for 1024 bytes.
|
* dst should have room for 1024 bytes.
|
||||||
*/
|
*/
|
||||||
unsigned px_acquire_system_randomness(uint8 *dst)
|
unsigned
|
||||||
|
px_acquire_system_randomness(uint8 *dst)
|
||||||
{
|
{
|
||||||
uint8 *p = dst;
|
uint8 *p = dst;
|
||||||
|
|
||||||
#ifdef TRY_DEV_RANDOM
|
#ifdef TRY_DEV_RANDOM
|
||||||
p = try_dev_random(p);
|
p = try_dev_random(p);
|
||||||
#endif
|
#endif
|
||||||
|
@ -240,4 +242,3 @@ unsigned px_acquire_system_randomness(uint8 *dst)
|
||||||
#endif
|
#endif
|
||||||
return p - dst;
|
return p - dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* $OpenBSD: rijndael.c,v 1.6 2000/12/09 18:51:34 markus Exp $ */
|
/* $OpenBSD: rijndael.c,v 1.6 2000/12/09 18:51:34 markus Exp $ */
|
||||||
|
|
||||||
/* $PostgreSQL: pgsql/contrib/pgcrypto/rijndael.c,v 1.11 2005/07/11 15:07:59 tgl Exp $ */
|
/* $PostgreSQL: pgsql/contrib/pgcrypto/rijndael.c,v 1.12 2005/10/15 02:49:06 momjian Exp $ */
|
||||||
|
|
||||||
/* This is an independent implementation of the encryption algorithm: */
|
/* This is an independent implementation of the encryption algorithm: */
|
||||||
/* */
|
/* */
|
||||||
|
@ -91,7 +91,6 @@ static void gen_tabs(void);
|
||||||
|
|
||||||
#include "rijndael.tbl"
|
#include "rijndael.tbl"
|
||||||
#define tab_gen 1
|
#define tab_gen 1
|
||||||
|
|
||||||
#else /* !PRE_CALC_TABLES */
|
#else /* !PRE_CALC_TABLES */
|
||||||
|
|
||||||
static u1byte pow_tab[256];
|
static u1byte pow_tab[256];
|
||||||
|
@ -143,7 +142,6 @@ static u4byte tab_gen = 0;
|
||||||
il_tab[1][byte((bi)[((n) + 3) & 3],1)] ^ \
|
il_tab[1][byte((bi)[((n) + 3) & 3],1)] ^ \
|
||||||
il_tab[2][byte((bi)[((n) + 2) & 3],2)] ^ \
|
il_tab[2][byte((bi)[((n) + 2) & 3],2)] ^ \
|
||||||
il_tab[3][byte((bi)[((n) + 1) & 3],3)] ^ *((k) + (n))
|
il_tab[3][byte((bi)[((n) + 1) & 3],3)] ^ *((k) + (n))
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define ls_box(x) \
|
#define ls_box(x) \
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
*
|
*
|
||||||
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
|
* $From: sha2.c,v 1.1 2001/11/08 00:01:51 adg Exp adg $
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.4 2005/07/12 20:27:42 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.c,v 1.5 2005/10/15 02:49:06 momjian Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
@ -310,8 +310,18 @@ SHA256_Init(SHA256_CTX *context)
|
||||||
void
|
void
|
||||||
SHA256_Transform(SHA256_CTX * context, const uint8 *data)
|
SHA256_Transform(SHA256_CTX * context, const uint8 *data)
|
||||||
{
|
{
|
||||||
uint32 a, b, c, d, e, f, g, h, s0, s1;
|
uint32 a,
|
||||||
uint32 T1, *W256;
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
e,
|
||||||
|
f,
|
||||||
|
g,
|
||||||
|
h,
|
||||||
|
s0,
|
||||||
|
s1;
|
||||||
|
uint32 T1,
|
||||||
|
*W256;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
W256 = (uint32 *) context->buffer;
|
W256 = (uint32 *) context->buffer;
|
||||||
|
@ -327,7 +337,8 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
|
||||||
h = context->state[7];
|
h = context->state[7];
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
/* Rounds 0 to 15 (unrolled): */
|
/* Rounds 0 to 15 (unrolled): */
|
||||||
ROUND256_0_TO_15(a, b, c, d, e, f, g, h);
|
ROUND256_0_TO_15(a, b, c, d, e, f, g, h);
|
||||||
ROUND256_0_TO_15(h, a, b, c, d, e, f, g);
|
ROUND256_0_TO_15(h, a, b, c, d, e, f, g);
|
||||||
|
@ -340,7 +351,8 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
|
||||||
} while (j < 16);
|
} while (j < 16);
|
||||||
|
|
||||||
/* Now for the remaining rounds to 64: */
|
/* Now for the remaining rounds to 64: */
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
ROUND256(a, b, c, d, e, f, g, h);
|
ROUND256(a, b, c, d, e, f, g, h);
|
||||||
ROUND256(h, a, b, c, d, e, f, g);
|
ROUND256(h, a, b, c, d, e, f, g);
|
||||||
ROUND256(g, h, a, b, c, d, e, f);
|
ROUND256(g, h, a, b, c, d, e, f);
|
||||||
|
@ -364,14 +376,24 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
a = b = c = d = e = f = g = h = T1 = 0;
|
a = b = c = d = e = f = g = h = T1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* SHA2_UNROLL_TRANSFORM */
|
#else /* SHA2_UNROLL_TRANSFORM */
|
||||||
|
|
||||||
void
|
void
|
||||||
SHA256_Transform(SHA256_CTX * context, const uint8 *data)
|
SHA256_Transform(SHA256_CTX * context, const uint8 *data)
|
||||||
{
|
{
|
||||||
uint32 a, b, c, d, e, f, g, h, s0, s1;
|
uint32 a,
|
||||||
uint32 T1, T2, *W256;
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
e,
|
||||||
|
f,
|
||||||
|
g,
|
||||||
|
h,
|
||||||
|
s0,
|
||||||
|
s1;
|
||||||
|
uint32 T1,
|
||||||
|
T2,
|
||||||
|
*W256;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
W256 = (uint32 *) context->buffer;
|
W256 = (uint32 *) context->buffer;
|
||||||
|
@ -387,7 +409,8 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
|
||||||
h = context->state[7];
|
h = context->state[7];
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
W256[j] = (uint32) data[3] | ((uint32) data[2] << 8) |
|
W256[j] = (uint32) data[3] | ((uint32) data[2] << 8) |
|
||||||
((uint32) data[1] << 16) | ((uint32) data[0] << 24);
|
((uint32) data[1] << 16) | ((uint32) data[0] << 24);
|
||||||
data += 4;
|
data += 4;
|
||||||
|
@ -406,7 +429,8 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
|
||||||
j++;
|
j++;
|
||||||
} while (j < 16);
|
} while (j < 16);
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
/* Part of the message block expansion: */
|
/* Part of the message block expansion: */
|
||||||
s0 = W256[(j + 1) & 0x0f];
|
s0 = W256[(j + 1) & 0x0f];
|
||||||
s0 = sigma0_256(s0);
|
s0 = sigma0_256(s0);
|
||||||
|
@ -442,31 +466,35 @@ SHA256_Transform(SHA256_CTX *context, const uint8 *data)
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
a = b = c = d = e = f = g = h = T1 = T2 = 0;
|
a = b = c = d = e = f = g = h = T1 = T2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SHA2_UNROLL_TRANSFORM */
|
#endif /* SHA2_UNROLL_TRANSFORM */
|
||||||
|
|
||||||
void
|
void
|
||||||
SHA256_Update(SHA256_CTX * context, const uint8 *data, size_t len)
|
SHA256_Update(SHA256_CTX * context, const uint8 *data, size_t len)
|
||||||
{
|
{
|
||||||
size_t freespace, usedspace;
|
size_t freespace,
|
||||||
|
usedspace;
|
||||||
|
|
||||||
/* Calling with no data is valid (we do nothing) */
|
/* Calling with no data is valid (we do nothing) */
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
|
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
|
||||||
if (usedspace > 0) {
|
if (usedspace > 0)
|
||||||
|
{
|
||||||
/* Calculate how much free space is available in the buffer */
|
/* Calculate how much free space is available in the buffer */
|
||||||
freespace = SHA256_BLOCK_LENGTH - usedspace;
|
freespace = SHA256_BLOCK_LENGTH - usedspace;
|
||||||
|
|
||||||
if (len >= freespace) {
|
if (len >= freespace)
|
||||||
|
{
|
||||||
/* Fill the buffer completely and process it */
|
/* Fill the buffer completely and process it */
|
||||||
memcpy(&context->buffer[usedspace], data, freespace);
|
memcpy(&context->buffer[usedspace], data, freespace);
|
||||||
context->bitcount += freespace << 3;
|
context->bitcount += freespace << 3;
|
||||||
len -= freespace;
|
len -= freespace;
|
||||||
data += freespace;
|
data += freespace;
|
||||||
SHA256_Transform(context, context->buffer);
|
SHA256_Transform(context, context->buffer);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* The buffer is not yet full */
|
/* The buffer is not yet full */
|
||||||
memcpy(&context->buffer[usedspace], data, len);
|
memcpy(&context->buffer[usedspace], data, len);
|
||||||
context->bitcount += len << 3;
|
context->bitcount += len << 3;
|
||||||
|
@ -475,14 +503,16 @@ SHA256_Update(SHA256_CTX *context, const uint8 *data, size_t len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (len >= SHA256_BLOCK_LENGTH) {
|
while (len >= SHA256_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
/* Process as many complete blocks as we can */
|
/* Process as many complete blocks as we can */
|
||||||
SHA256_Transform(context, data);
|
SHA256_Transform(context, data);
|
||||||
context->bitcount += SHA256_BLOCK_LENGTH << 3;
|
context->bitcount += SHA256_BLOCK_LENGTH << 3;
|
||||||
len -= SHA256_BLOCK_LENGTH;
|
len -= SHA256_BLOCK_LENGTH;
|
||||||
data += SHA256_BLOCK_LENGTH;
|
data += SHA256_BLOCK_LENGTH;
|
||||||
}
|
}
|
||||||
if (len > 0) {
|
if (len > 0)
|
||||||
|
{
|
||||||
/* There's left-overs, so save 'em */
|
/* There's left-overs, so save 'em */
|
||||||
memcpy(context->buffer, data, len);
|
memcpy(context->buffer, data, len);
|
||||||
context->bitcount += len << 3;
|
context->bitcount += len << 3;
|
||||||
|
@ -497,21 +527,27 @@ SHA256_Final(uint8 digest[], SHA256_CTX *context)
|
||||||
unsigned int usedspace;
|
unsigned int usedspace;
|
||||||
|
|
||||||
/* If no digest buffer is passed, we don't bother doing this: */
|
/* If no digest buffer is passed, we don't bother doing this: */
|
||||||
if (digest != NULL) {
|
if (digest != NULL)
|
||||||
|
{
|
||||||
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
|
usedspace = (context->bitcount >> 3) % SHA256_BLOCK_LENGTH;
|
||||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||||
/* Convert FROM host byte order */
|
/* Convert FROM host byte order */
|
||||||
REVERSE64(context->bitcount, context->bitcount);
|
REVERSE64(context->bitcount, context->bitcount);
|
||||||
#endif
|
#endif
|
||||||
if (usedspace > 0) {
|
if (usedspace > 0)
|
||||||
|
{
|
||||||
/* Begin padding with a 1 bit: */
|
/* Begin padding with a 1 bit: */
|
||||||
context->buffer[usedspace++] = 0x80;
|
context->buffer[usedspace++] = 0x80;
|
||||||
|
|
||||||
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH) {
|
if (usedspace <= SHA256_SHORT_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
/* Set-up for the last transform: */
|
/* Set-up for the last transform: */
|
||||||
memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace);
|
memset(&context->buffer[usedspace], 0, SHA256_SHORT_BLOCK_LENGTH - usedspace);
|
||||||
} else {
|
}
|
||||||
if (usedspace < SHA256_BLOCK_LENGTH) {
|
else
|
||||||
|
{
|
||||||
|
if (usedspace < SHA256_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace);
|
memset(&context->buffer[usedspace], 0, SHA256_BLOCK_LENGTH - usedspace);
|
||||||
}
|
}
|
||||||
/* Do second-to-last transform: */
|
/* Do second-to-last transform: */
|
||||||
|
@ -520,7 +556,9 @@ SHA256_Final(uint8 digest[], SHA256_CTX *context)
|
||||||
/* And set-up for the last transform: */
|
/* And set-up for the last transform: */
|
||||||
memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
|
memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Set-up for the last transform: */
|
/* Set-up for the last transform: */
|
||||||
memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
|
memset(context->buffer, 0, SHA256_SHORT_BLOCK_LENGTH);
|
||||||
|
|
||||||
|
@ -537,7 +575,9 @@ SHA256_Final(uint8 digest[], SHA256_CTX *context)
|
||||||
{
|
{
|
||||||
/* Convert TO host byte order */
|
/* Convert TO host byte order */
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
REVERSE32(context->state[j], context->state[j]);
|
REVERSE32(context->state[j], context->state[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -594,8 +634,18 @@ SHA512_Init(SHA512_CTX *context)
|
||||||
void
|
void
|
||||||
SHA512_Transform(SHA512_CTX * context, const uint8 *data)
|
SHA512_Transform(SHA512_CTX * context, const uint8 *data)
|
||||||
{
|
{
|
||||||
uint64 a, b, c, d, e, f, g, h, s0, s1;
|
uint64 a,
|
||||||
uint64 T1, *W512 = (uint64 *)context->buffer;
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
e,
|
||||||
|
f,
|
||||||
|
g,
|
||||||
|
h,
|
||||||
|
s0,
|
||||||
|
s1;
|
||||||
|
uint64 T1,
|
||||||
|
*W512 = (uint64 *) context->buffer;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/* Initialize registers with the prev. intermediate value */
|
/* Initialize registers with the prev. intermediate value */
|
||||||
|
@ -609,7 +659,8 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
|
||||||
h = context->state[7];
|
h = context->state[7];
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
ROUND512_0_TO_15(a, b, c, d, e, f, g, h);
|
ROUND512_0_TO_15(a, b, c, d, e, f, g, h);
|
||||||
ROUND512_0_TO_15(h, a, b, c, d, e, f, g);
|
ROUND512_0_TO_15(h, a, b, c, d, e, f, g);
|
||||||
ROUND512_0_TO_15(g, h, a, b, c, d, e, f);
|
ROUND512_0_TO_15(g, h, a, b, c, d, e, f);
|
||||||
|
@ -621,7 +672,8 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
|
||||||
} while (j < 16);
|
} while (j < 16);
|
||||||
|
|
||||||
/* Now for the remaining rounds up to 79: */
|
/* Now for the remaining rounds up to 79: */
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
ROUND512(a, b, c, d, e, f, g, h);
|
ROUND512(a, b, c, d, e, f, g, h);
|
||||||
ROUND512(h, a, b, c, d, e, f, g);
|
ROUND512(h, a, b, c, d, e, f, g);
|
||||||
ROUND512(g, h, a, b, c, d, e, f);
|
ROUND512(g, h, a, b, c, d, e, f);
|
||||||
|
@ -645,14 +697,24 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
a = b = c = d = e = f = g = h = T1 = 0;
|
a = b = c = d = e = f = g = h = T1 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#else /* SHA2_UNROLL_TRANSFORM */
|
#else /* SHA2_UNROLL_TRANSFORM */
|
||||||
|
|
||||||
void
|
void
|
||||||
SHA512_Transform(SHA512_CTX * context, const uint8 *data)
|
SHA512_Transform(SHA512_CTX * context, const uint8 *data)
|
||||||
{
|
{
|
||||||
uint64 a, b, c, d, e, f, g, h, s0, s1;
|
uint64 a,
|
||||||
uint64 T1, T2, *W512 = (uint64 *)context->buffer;
|
b,
|
||||||
|
c,
|
||||||
|
d,
|
||||||
|
e,
|
||||||
|
f,
|
||||||
|
g,
|
||||||
|
h,
|
||||||
|
s0,
|
||||||
|
s1;
|
||||||
|
uint64 T1,
|
||||||
|
T2,
|
||||||
|
*W512 = (uint64 *) context->buffer;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/* Initialize registers with the prev. intermediate value */
|
/* Initialize registers with the prev. intermediate value */
|
||||||
|
@ -666,7 +728,8 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
|
||||||
h = context->state[7];
|
h = context->state[7];
|
||||||
|
|
||||||
j = 0;
|
j = 0;
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
W512[j] = (uint64) data[7] | ((uint64) data[6] << 8) |
|
W512[j] = (uint64) data[7] | ((uint64) data[6] << 8) |
|
||||||
((uint64) data[5] << 16) | ((uint64) data[4] << 24) |
|
((uint64) data[5] << 16) | ((uint64) data[4] << 24) |
|
||||||
((uint64) data[3] << 32) | ((uint64) data[2] << 40) |
|
((uint64) data[3] << 32) | ((uint64) data[2] << 40) |
|
||||||
|
@ -687,7 +750,8 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
|
||||||
j++;
|
j++;
|
||||||
} while (j < 16);
|
} while (j < 16);
|
||||||
|
|
||||||
do {
|
do
|
||||||
|
{
|
||||||
/* Part of the message block expansion: */
|
/* Part of the message block expansion: */
|
||||||
s0 = W512[(j + 1) & 0x0f];
|
s0 = W512[(j + 1) & 0x0f];
|
||||||
s0 = sigma0_512(s0);
|
s0 = sigma0_512(s0);
|
||||||
|
@ -723,31 +787,35 @@ SHA512_Transform(SHA512_CTX *context, const uint8 *data)
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
a = b = c = d = e = f = g = h = T1 = T2 = 0;
|
a = b = c = d = e = f = g = h = T1 = T2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* SHA2_UNROLL_TRANSFORM */
|
#endif /* SHA2_UNROLL_TRANSFORM */
|
||||||
|
|
||||||
void
|
void
|
||||||
SHA512_Update(SHA512_CTX * context, const uint8 *data, size_t len)
|
SHA512_Update(SHA512_CTX * context, const uint8 *data, size_t len)
|
||||||
{
|
{
|
||||||
size_t freespace, usedspace;
|
size_t freespace,
|
||||||
|
usedspace;
|
||||||
|
|
||||||
/* Calling with no data is valid (we do nothing) */
|
/* Calling with no data is valid (we do nothing) */
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
|
usedspace = (context->bitcount[0] >> 3) % SHA512_BLOCK_LENGTH;
|
||||||
if (usedspace > 0) {
|
if (usedspace > 0)
|
||||||
|
{
|
||||||
/* Calculate how much free space is available in the buffer */
|
/* Calculate how much free space is available in the buffer */
|
||||||
freespace = SHA512_BLOCK_LENGTH - usedspace;
|
freespace = SHA512_BLOCK_LENGTH - usedspace;
|
||||||
|
|
||||||
if (len >= freespace) {
|
if (len >= freespace)
|
||||||
|
{
|
||||||
/* Fill the buffer completely and process it */
|
/* Fill the buffer completely and process it */
|
||||||
memcpy(&context->buffer[usedspace], data, freespace);
|
memcpy(&context->buffer[usedspace], data, freespace);
|
||||||
ADDINC128(context->bitcount, freespace << 3);
|
ADDINC128(context->bitcount, freespace << 3);
|
||||||
len -= freespace;
|
len -= freespace;
|
||||||
data += freespace;
|
data += freespace;
|
||||||
SHA512_Transform(context, context->buffer);
|
SHA512_Transform(context, context->buffer);
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* The buffer is not yet full */
|
/* The buffer is not yet full */
|
||||||
memcpy(&context->buffer[usedspace], data, len);
|
memcpy(&context->buffer[usedspace], data, len);
|
||||||
ADDINC128(context->bitcount, len << 3);
|
ADDINC128(context->bitcount, len << 3);
|
||||||
|
@ -756,14 +824,16 @@ SHA512_Update(SHA512_CTX *context, const uint8 *data, size_t len)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (len >= SHA512_BLOCK_LENGTH) {
|
while (len >= SHA512_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
/* Process as many complete blocks as we can */
|
/* Process as many complete blocks as we can */
|
||||||
SHA512_Transform(context, data);
|
SHA512_Transform(context, data);
|
||||||
ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
|
ADDINC128(context->bitcount, SHA512_BLOCK_LENGTH << 3);
|
||||||
len -= SHA512_BLOCK_LENGTH;
|
len -= SHA512_BLOCK_LENGTH;
|
||||||
data += SHA512_BLOCK_LENGTH;
|
data += SHA512_BLOCK_LENGTH;
|
||||||
}
|
}
|
||||||
if (len > 0) {
|
if (len > 0)
|
||||||
|
{
|
||||||
/* There's left-overs, so save 'em */
|
/* There's left-overs, so save 'em */
|
||||||
memcpy(context->buffer, data, len);
|
memcpy(context->buffer, data, len);
|
||||||
ADDINC128(context->bitcount, len << 3);
|
ADDINC128(context->bitcount, len << 3);
|
||||||
|
@ -783,15 +853,20 @@ SHA512_Last(SHA512_CTX *context)
|
||||||
REVERSE64(context->bitcount[0], context->bitcount[0]);
|
REVERSE64(context->bitcount[0], context->bitcount[0]);
|
||||||
REVERSE64(context->bitcount[1], context->bitcount[1]);
|
REVERSE64(context->bitcount[1], context->bitcount[1]);
|
||||||
#endif
|
#endif
|
||||||
if (usedspace > 0) {
|
if (usedspace > 0)
|
||||||
|
{
|
||||||
/* Begin padding with a 1 bit: */
|
/* Begin padding with a 1 bit: */
|
||||||
context->buffer[usedspace++] = 0x80;
|
context->buffer[usedspace++] = 0x80;
|
||||||
|
|
||||||
if (usedspace <= SHA512_SHORT_BLOCK_LENGTH) {
|
if (usedspace <= SHA512_SHORT_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
/* Set-up for the last transform: */
|
/* Set-up for the last transform: */
|
||||||
memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace);
|
memset(&context->buffer[usedspace], 0, SHA512_SHORT_BLOCK_LENGTH - usedspace);
|
||||||
} else {
|
}
|
||||||
if (usedspace < SHA512_BLOCK_LENGTH) {
|
else
|
||||||
|
{
|
||||||
|
if (usedspace < SHA512_BLOCK_LENGTH)
|
||||||
|
{
|
||||||
memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace);
|
memset(&context->buffer[usedspace], 0, SHA512_BLOCK_LENGTH - usedspace);
|
||||||
}
|
}
|
||||||
/* Do second-to-last transform: */
|
/* Do second-to-last transform: */
|
||||||
|
@ -800,7 +875,9 @@ SHA512_Last(SHA512_CTX *context)
|
||||||
/* And set-up for the last transform: */
|
/* And set-up for the last transform: */
|
||||||
memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2);
|
memset(context->buffer, 0, SHA512_BLOCK_LENGTH - 2);
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
/* Prepare for final transform: */
|
/* Prepare for final transform: */
|
||||||
memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH);
|
memset(context->buffer, 0, SHA512_SHORT_BLOCK_LENGTH);
|
||||||
|
|
||||||
|
@ -819,7 +896,8 @@ void
|
||||||
SHA512_Final(uint8 digest[], SHA512_CTX * context)
|
SHA512_Final(uint8 digest[], SHA512_CTX * context)
|
||||||
{
|
{
|
||||||
/* If no digest buffer is passed, we don't bother doing this: */
|
/* If no digest buffer is passed, we don't bother doing this: */
|
||||||
if (digest != NULL) {
|
if (digest != NULL)
|
||||||
|
{
|
||||||
SHA512_Last(context);
|
SHA512_Last(context);
|
||||||
|
|
||||||
/* Save the hash data for output: */
|
/* Save the hash data for output: */
|
||||||
|
@ -827,7 +905,9 @@ SHA512_Final(uint8 digest[], SHA512_CTX *context)
|
||||||
{
|
{
|
||||||
/* Convert TO host byte order */
|
/* Convert TO host byte order */
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 8; j++) {
|
|
||||||
|
for (j = 0; j < 8; j++)
|
||||||
|
{
|
||||||
REVERSE64(context->state[j], context->state[j]);
|
REVERSE64(context->state[j], context->state[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -861,7 +941,8 @@ void
|
||||||
SHA384_Final(uint8 digest[], SHA384_CTX * context)
|
SHA384_Final(uint8 digest[], SHA384_CTX * context)
|
||||||
{
|
{
|
||||||
/* If no digest buffer is passed, we don't bother doing this: */
|
/* If no digest buffer is passed, we don't bother doing this: */
|
||||||
if (digest != NULL) {
|
if (digest != NULL)
|
||||||
|
{
|
||||||
SHA512_Last((SHA512_CTX *) context);
|
SHA512_Last((SHA512_CTX *) context);
|
||||||
|
|
||||||
/* Save the hash data for output: */
|
/* Save the hash data for output: */
|
||||||
|
@ -869,7 +950,9 @@ SHA384_Final(uint8 digest[], SHA384_CTX *context)
|
||||||
{
|
{
|
||||||
/* Convert TO host byte order */
|
/* Convert TO host byte order */
|
||||||
int j;
|
int j;
|
||||||
for (j = 0; j < 6; j++) {
|
|
||||||
|
for (j = 0; j < 6; j++)
|
||||||
|
{
|
||||||
REVERSE64(context->state[j], context->state[j]);
|
REVERSE64(context->state[j], context->state[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
/* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.h,v 1.1 2005/07/10 13:46:29 momjian Exp $ */
|
/* $PostgreSQL: pgsql/contrib/pgcrypto/sha2.h,v 1.2 2005/10/15 02:49:06 momjian Exp $ */
|
||||||
/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */
|
/* $OpenBSD: sha2.h,v 1.2 2004/04/28 23:11:57 millert Exp $ */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -52,12 +52,14 @@
|
||||||
|
|
||||||
|
|
||||||
/*** SHA-256/384/512 Context Structures *******************************/
|
/*** SHA-256/384/512 Context Structures *******************************/
|
||||||
typedef struct _SHA256_CTX {
|
typedef struct _SHA256_CTX
|
||||||
|
{
|
||||||
uint32 state[8];
|
uint32 state[8];
|
||||||
uint64 bitcount;
|
uint64 bitcount;
|
||||||
uint8 buffer[SHA256_BLOCK_LENGTH];
|
uint8 buffer[SHA256_BLOCK_LENGTH];
|
||||||
} SHA256_CTX;
|
} SHA256_CTX;
|
||||||
typedef struct _SHA512_CTX {
|
typedef struct _SHA512_CTX
|
||||||
|
{
|
||||||
uint64 state[8];
|
uint64 state[8];
|
||||||
uint64 bitcount[2];
|
uint64 bitcount[2];
|
||||||
uint8 buffer[SHA512_BLOCK_LENGTH];
|
uint8 buffer[SHA512_BLOCK_LENGTH];
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.19 2005/05/30 23:09:06 tgl Exp $
|
* $PostgreSQL: pgsql/contrib/pgstattuple/pgstattuple.c,v 1.20 2005/10/15 02:49:06 momjian Exp $
|
||||||
*
|
*
|
||||||
* Copyright (c) 2001,2002 Tatsuo Ishii
|
* Copyright (c) 2001,2002 Tatsuo Ishii
|
||||||
*
|
*
|
||||||
|
@ -123,8 +123,8 @@ pgstattuple_real(Relation rel, FunctionCallInfo fcinfo)
|
||||||
tupdesc = CreateTupleDescCopy(tupdesc);
|
tupdesc = CreateTupleDescCopy(tupdesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate attribute metadata needed later to produce tuples from raw
|
* Generate attribute metadata needed later to produce tuples from raw C
|
||||||
* C strings
|
* strings
|
||||||
*/
|
*/
|
||||||
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||||
|
|
||||||
|
@ -197,9 +197,9 @@ pgstattuple_real(Relation rel, FunctionCallInfo fcinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare a values array for constructing the tuple. This should be
|
* Prepare a values array for constructing the tuple. This should be an
|
||||||
* an array of C strings which will be processed later by the
|
* array of C strings which will be processed later by the appropriate
|
||||||
* appropriate "in" functions.
|
* "in" functions.
|
||||||
*/
|
*/
|
||||||
values = (char **) palloc(NCOLUMNS * sizeof(char *));
|
values = (char **) palloc(NCOLUMNS * sizeof(char *));
|
||||||
for (i = 0; i < NCOLUMNS; i++)
|
for (i = 0; i < NCOLUMNS; i++)
|
||||||
|
|
|
@ -124,8 +124,7 @@ seg_out(SEG * seg)
|
||||||
if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
|
if (seg->lower == seg->upper && seg->l_ext == seg->u_ext)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* indicates that this interval was built by seg_in off a single
|
* indicates that this interval was built by seg_in off a single point
|
||||||
* point
|
|
||||||
*/
|
*/
|
||||||
p += restore(p, seg->lower, seg->l_sigd);
|
p += restore(p, seg->lower, seg->l_sigd);
|
||||||
}
|
}
|
||||||
|
@ -349,8 +348,7 @@ gseg_picksplit(GistEntryVector *entryvec,
|
||||||
size_waste = size_union - size_inter;
|
size_waste = size_union - size_inter;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* are these a more promising split that what we've already
|
* are these a more promising split that what we've already seen?
|
||||||
* seen?
|
|
||||||
*/
|
*/
|
||||||
if (size_waste > waste || firsttime)
|
if (size_waste > waste || firsttime)
|
||||||
{
|
{
|
||||||
|
@ -375,24 +373,24 @@ gseg_picksplit(GistEntryVector *entryvec,
|
||||||
rt_seg_size(datum_r, &size_r);
|
rt_seg_size(datum_r, &size_r);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now split up the regions between the two seeds. An important
|
* Now split up the regions between the two seeds. An important property
|
||||||
* property of this split algorithm is that the split vector v has the
|
* of this split algorithm is that the split vector v has the indices of
|
||||||
* indices of items to be split in order in its left and right
|
* items to be split in order in its left and right vectors. We exploit
|
||||||
* vectors. We exploit this property by doing a merge in the code
|
* this property by doing a merge in the code that actually splits the
|
||||||
* that actually splits the page.
|
* page.
|
||||||
*
|
*
|
||||||
* For efficiency, we also place the new index tuple in this loop. This
|
* For efficiency, we also place the new index tuple in this loop. This is
|
||||||
* is handled at the very end, when we have placed all the existing
|
* handled at the very end, when we have placed all the existing tuples
|
||||||
* tuples and i == maxoff + 1.
|
* and i == maxoff + 1.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
maxoff = OffsetNumberNext(maxoff);
|
maxoff = OffsetNumberNext(maxoff);
|
||||||
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
for (i = FirstOffsetNumber; i <= maxoff; i = OffsetNumberNext(i))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* If we've already decided where to place this item, just put it
|
* If we've already decided where to place this item, just put it on
|
||||||
* on the right list. Otherwise, we need to figure out which page
|
* the right list. Otherwise, we need to figure out which page needs
|
||||||
* needs the least enlargement in order to store the item.
|
* the least enlargement in order to store the item.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (i == seed_1)
|
if (i == seed_1)
|
||||||
|
@ -742,8 +740,8 @@ seg_cmp(SEG * a, SEG * b)
|
||||||
* a->lower == b->lower, so consider type of boundary.
|
* a->lower == b->lower, so consider type of boundary.
|
||||||
*
|
*
|
||||||
* A '-' lower bound is < any other kind (this could only be relevant if
|
* A '-' lower bound is < any other kind (this could only be relevant if
|
||||||
* -HUGE_VAL is used as a regular data value). A '<' lower bound is <
|
* -HUGE_VAL is used as a regular data value). A '<' lower bound is < any
|
||||||
* any other kind except '-'. A '>' lower bound is > any other kind.
|
* other kind except '-'. A '>' lower bound is > any other kind.
|
||||||
*/
|
*/
|
||||||
if (a->l_ext != b->l_ext)
|
if (a->l_ext != b->l_ext)
|
||||||
{
|
{
|
||||||
|
@ -764,8 +762,7 @@ seg_cmp(SEG * a, SEG * b)
|
||||||
/*
|
/*
|
||||||
* For other boundary types, consider # of significant digits first.
|
* For other boundary types, consider # of significant digits first.
|
||||||
*/
|
*/
|
||||||
if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include
|
if (a->l_sigd < b->l_sigd) /* (a) is blurred and is likely to include (b) */
|
||||||
* (b) */
|
|
||||||
return -1;
|
return -1;
|
||||||
if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
|
if (a->l_sigd > b->l_sigd) /* (a) is less blurred and is likely to be
|
||||||
* included in (b) */
|
* included in (b) */
|
||||||
|
@ -800,8 +797,8 @@ seg_cmp(SEG * a, SEG * b)
|
||||||
* a->upper == b->upper, so consider type of boundary.
|
* a->upper == b->upper, so consider type of boundary.
|
||||||
*
|
*
|
||||||
* A '-' upper bound is > any other kind (this could only be relevant if
|
* A '-' upper bound is > any other kind (this could only be relevant if
|
||||||
* HUGE_VAL is used as a regular data value). A '<' upper bound is <
|
* HUGE_VAL is used as a regular data value). A '<' upper bound is < any
|
||||||
* any other kind. A '>' upper bound is > any other kind except '-'.
|
* other kind. A '>' upper bound is > any other kind except '-'.
|
||||||
*/
|
*/
|
||||||
if (a->u_ext != b->u_ext)
|
if (a->u_ext != b->u_ext)
|
||||||
{
|
{
|
||||||
|
@ -820,11 +817,10 @@ seg_cmp(SEG * a, SEG * b)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For other boundary types, consider # of significant digits first.
|
* For other boundary types, consider # of significant digits first. Note
|
||||||
* Note result here is converse of the lower-boundary case.
|
* result here is converse of the lower-boundary case.
|
||||||
*/
|
*/
|
||||||
if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include
|
if (a->u_sigd < b->u_sigd) /* (a) is blurred and is likely to include (b) */
|
||||||
* (b) */
|
|
||||||
return 1;
|
return 1;
|
||||||
if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
|
if (a->u_sigd > b->u_sigd) /* (a) is less blurred and is likely to be
|
||||||
* included in (b) */
|
* included in (b) */
|
||||||
|
@ -908,17 +904,17 @@ restore(char *result, float val, int n)
|
||||||
sign;
|
sign;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* put a cap on the number of siugnificant digits to avoid nonsense in
|
* put a cap on the number of siugnificant digits to avoid nonsense in the
|
||||||
* the output
|
* output
|
||||||
*/
|
*/
|
||||||
n = Min(n, FLT_DIG);
|
n = Min(n, FLT_DIG);
|
||||||
|
|
||||||
/* remember the sign */
|
/* remember the sign */
|
||||||
sign = (val < 0 ? 1 : 0);
|
sign = (val < 0 ? 1 : 0);
|
||||||
|
|
||||||
efmt[5] = '0' + (n - 1) % 10; /* makes %-15.(n-1)e -- this
|
efmt[5] = '0' + (n - 1) % 10; /* makes %-15.(n-1)e -- this format
|
||||||
* format guarantees that the
|
* guarantees that the exponent is
|
||||||
* exponent is always present */
|
* always present */
|
||||||
|
|
||||||
sprintf(result, efmt, val);
|
sprintf(result, efmt, val);
|
||||||
|
|
||||||
|
@ -940,8 +936,8 @@ restore(char *result, float val, int n)
|
||||||
if (Abs(exp) <= 4)
|
if (Abs(exp) <= 4)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* remove the decimal point from the mantyssa and write the
|
* remove the decimal point from the mantyssa and write the digits
|
||||||
* digits to the buf array
|
* to the buf array
|
||||||
*/
|
*/
|
||||||
for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
|
for (p = result + sign, i = 10, dp = 0; *p != 'e'; p++, i++)
|
||||||
{
|
{
|
||||||
|
@ -960,10 +956,9 @@ restore(char *result, float val, int n)
|
||||||
if (dp - 10 + exp >= n)
|
if (dp - 10 + exp >= n)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* the decimal point is behind the last significant
|
* the decimal point is behind the last significant digit;
|
||||||
* digit; the digits in between must be converted to
|
* the digits in between must be converted to the exponent
|
||||||
* the exponent and the decimal point placed after the
|
* and the decimal point placed after the first digit
|
||||||
* first digit
|
|
||||||
*/
|
*/
|
||||||
exp = dp - 10 + exp - n;
|
exp = dp - 10 + exp - n;
|
||||||
buf[10 + n] = '\0';
|
buf[10 + n] = '\0';
|
||||||
|
@ -978,8 +973,8 @@ restore(char *result, float val, int n)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* adjust the exponent by the number of digits after
|
* adjust the exponent by the number of digits after the
|
||||||
* the decimal point
|
* decimal point
|
||||||
*/
|
*/
|
||||||
if (n > 1)
|
if (n > 1)
|
||||||
sprintf(&buf[11 + n], "e%d", exp + n - 1);
|
sprintf(&buf[11 + n], "e%d", exp + n - 1);
|
||||||
|
|
|
@ -76,9 +76,8 @@ moddatetime(PG_FUNCTION_ARGS)
|
||||||
Int32GetDatum(-1));
|
Int32GetDatum(-1));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This gets the position in the tuple of the field we want. args[0]
|
* This gets the position in the tuple of the field we want. args[0] being
|
||||||
* being the name of the field to update, as passed in from the
|
* the name of the field to update, as passed in from the trigger.
|
||||||
* trigger.
|
|
||||||
*/
|
*/
|
||||||
attnum = SPI_fnumber(tupdesc, args[0]);
|
attnum = SPI_fnumber(tupdesc, args[0]);
|
||||||
|
|
||||||
|
|
|
@ -114,8 +114,8 @@ check_primary_key(PG_FUNCTION_ARGS)
|
||||||
kvals = (Datum *) palloc(nkeys * sizeof(Datum));
|
kvals = (Datum *) palloc(nkeys * sizeof(Datum));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct ident string as TriggerName $ TriggeredRelationId and try
|
* Construct ident string as TriggerName $ TriggeredRelationId and try to
|
||||||
* to find prepared execution plan.
|
* find prepared execution plan.
|
||||||
*/
|
*/
|
||||||
snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
|
snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
|
||||||
plan = find_plan(ident, &PPlans, &nPPlans);
|
plan = find_plan(ident, &PPlans, &nPPlans);
|
||||||
|
@ -141,9 +141,9 @@ check_primary_key(PG_FUNCTION_ARGS)
|
||||||
kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
|
kvals[i] = SPI_getbinval(tuple, tupdesc, fnumber, &isnull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's NULL then nothing to do! DON'T FORGET call SPI_finish
|
* If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()!
|
||||||
* ()! DON'T FORGET return tuple! Executor inserts tuple you're
|
* DON'T FORGET return tuple! Executor inserts tuple you're returning!
|
||||||
* returning! If you return NULL then nothing will be inserted!
|
* If you return NULL then nothing will be inserted!
|
||||||
*/
|
*/
|
||||||
if (isnull)
|
if (isnull)
|
||||||
{
|
{
|
||||||
|
@ -164,8 +164,8 @@ check_primary_key(PG_FUNCTION_ARGS)
|
||||||
char sql[8192];
|
char sql[8192];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct query: SELECT 1 FROM _referenced_relation_ WHERE
|
* Construct query: SELECT 1 FROM _referenced_relation_ WHERE Pkey1 =
|
||||||
* Pkey1 = $1 [AND Pkey2 = $2 [...]]
|
* $1 [AND Pkey2 = $2 [...]]
|
||||||
*/
|
*/
|
||||||
snprintf(sql, sizeof(sql), "select 1 from %s where ", relname);
|
snprintf(sql, sizeof(sql), "select 1 from %s where ", relname);
|
||||||
for (i = 0; i < nkeys; i++)
|
for (i = 0; i < nkeys; i++)
|
||||||
|
@ -181,9 +181,8 @@ check_primary_key(PG_FUNCTION_ARGS)
|
||||||
elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result);
|
elog(ERROR, "check_primary_key: SPI_prepare returned %d", SPI_result);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remember that SPI_prepare places plan in current memory context
|
* Remember that SPI_prepare places plan in current memory context -
|
||||||
* - so, we have to save plan in Top memory context for latter
|
* so, we have to save plan in Top memory context for latter use.
|
||||||
* use.
|
|
||||||
*/
|
*/
|
||||||
pplan = SPI_saveplan(pplan);
|
pplan = SPI_saveplan(pplan);
|
||||||
if (pplan == NULL)
|
if (pplan == NULL)
|
||||||
|
@ -252,8 +251,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
EPlan *plan; /* prepared plan(s) */
|
EPlan *plan; /* prepared plan(s) */
|
||||||
Oid *argtypes = NULL; /* key types to prepare execution plan */
|
Oid *argtypes = NULL; /* key types to prepare execution plan */
|
||||||
bool isnull; /* to know is some column NULL or not */
|
bool isnull; /* to know is some column NULL or not */
|
||||||
bool isequal = true; /* are keys in both tuples equal (in
|
bool isequal = true; /* are keys in both tuples equal (in UPDATE) */
|
||||||
* UPDATE) */
|
|
||||||
char ident[2 * NAMEDATALEN]; /* to identify myself */
|
char ident[2 * NAMEDATALEN]; /* to identify myself */
|
||||||
int is_update = 0;
|
int is_update = 0;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -287,9 +285,8 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
trigtuple = trigdata->tg_trigtuple;
|
trigtuple = trigdata->tg_trigtuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* But if this is UPDATE then we have to return tg_newtuple. Also, if
|
* But if this is UPDATE then we have to return tg_newtuple. Also, if key
|
||||||
* key in tg_newtuple is the same as in tg_trigtuple then nothing to
|
* in tg_newtuple is the same as in tg_trigtuple then nothing to do.
|
||||||
* do.
|
|
||||||
*/
|
*/
|
||||||
is_update = 0;
|
is_update = 0;
|
||||||
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
||||||
|
@ -337,8 +334,8 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
kvals = (Datum *) palloc(nkeys * sizeof(Datum));
|
kvals = (Datum *) palloc(nkeys * sizeof(Datum));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct ident string as TriggerName $ TriggeredRelationId and try
|
* Construct ident string as TriggerName $ TriggeredRelationId and try to
|
||||||
* to find prepared execution plan(s).
|
* find prepared execution plan(s).
|
||||||
*/
|
*/
|
||||||
snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
|
snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
|
||||||
plan = find_plan(ident, &FPlans, &nFPlans);
|
plan = find_plan(ident, &FPlans, &nFPlans);
|
||||||
|
@ -372,9 +369,9 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
|
kvals[i] = SPI_getbinval(trigtuple, tupdesc, fnumber, &isnull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's NULL then nothing to do! DON'T FORGET call SPI_finish
|
* If it's NULL then nothing to do! DON'T FORGET call SPI_finish ()!
|
||||||
* ()! DON'T FORGET return tuple! Executor inserts tuple you're
|
* DON'T FORGET return tuple! Executor inserts tuple you're returning!
|
||||||
* returning! If you return NULL then nothing will be inserted!
|
* If you return NULL then nothing will be inserted!
|
||||||
*/
|
*/
|
||||||
if (isnull)
|
if (isnull)
|
||||||
{
|
{
|
||||||
|
@ -383,9 +380,9 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If UPDATE then get column value from new tuple being inserted
|
* If UPDATE then get column value from new tuple being inserted and
|
||||||
* and compare is this the same as old one. For the moment we use
|
* compare is this the same as old one. For the moment we use string
|
||||||
* string presentation of values...
|
* presentation of values...
|
||||||
*/
|
*/
|
||||||
if (newtuple != NULL)
|
if (newtuple != NULL)
|
||||||
{
|
{
|
||||||
|
@ -482,8 +479,7 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* is_char_type =1 i set ' ' for define a new
|
* is_char_type =1 i set ' ' for define a new value
|
||||||
* value
|
|
||||||
*/
|
*/
|
||||||
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
|
snprintf(sql + strlen(sql), sizeof(sql) - strlen(sql),
|
||||||
" %s = %s%s%s %s ",
|
" %s = %s%s%s %s ",
|
||||||
|
@ -503,8 +499,8 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
/*
|
/*
|
||||||
* For 'S'etnull action we construct UPDATE query - UPDATE
|
* For 'S'etnull action we construct UPDATE query - UPDATE
|
||||||
* _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
|
* _referencing_relation_ SET Fkey1 null [, Fkey2 null [...]]
|
||||||
* WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]] - to set key
|
* WHERE Fkey1 = $1 [AND Fkey2 = $2 [...]] - to set key columns in
|
||||||
* columns in all referencing tuples to NULL.
|
* all referencing tuples to NULL.
|
||||||
*/
|
*/
|
||||||
else if (action == 's')
|
else if (action == 's')
|
||||||
{
|
{
|
||||||
|
@ -532,9 +528,9 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
elog(ERROR, "check_foreign_key: SPI_prepare returned %d", SPI_result);
|
elog(ERROR, "check_foreign_key: SPI_prepare returned %d", SPI_result);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remember that SPI_prepare places plan in current memory
|
* Remember that SPI_prepare places plan in current memory context
|
||||||
* context - so, we have to save plan in Top memory context
|
* - so, we have to save plan in Top memory context for latter
|
||||||
* for latter use.
|
* use.
|
||||||
*/
|
*/
|
||||||
pplan = SPI_saveplan(pplan);
|
pplan = SPI_saveplan(pplan);
|
||||||
if (pplan == NULL)
|
if (pplan == NULL)
|
||||||
|
@ -566,8 +562,8 @@ check_foreign_key(PG_FUNCTION_ARGS)
|
||||||
for (r = 0; r < nrefs; r++)
|
for (r = 0; r < nrefs; r++)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* For 'R'estrict we may to execute plan for one tuple only, for
|
* For 'R'estrict we may to execute plan for one tuple only, for other
|
||||||
* other actions - for all tuples.
|
* actions - for all tuples.
|
||||||
*/
|
*/
|
||||||
int tcount = (action == 'r') ? 1 : 0;
|
int tcount = (action == 'r') ? 1 : 0;
|
||||||
|
|
||||||
|
|
|
@ -245,8 +245,8 @@ timetravel(PG_FUNCTION_ARGS)
|
||||||
elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]);
|
elog(ERROR, "timetravel (%s): %s must be NOT NULL", relname, args[a_time_off]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If DELETE/UPDATE of tuple with stop_date neq INFINITY then say
|
* If DELETE/UPDATE of tuple with stop_date neq INFINITY then say upper
|
||||||
* upper Executor to skip operation for this tuple
|
* Executor to skip operation for this tuple
|
||||||
*/
|
*/
|
||||||
if (newtuple != NULL)
|
if (newtuple != NULL)
|
||||||
{ /* UPDATE */
|
{ /* UPDATE */
|
||||||
|
@ -263,8 +263,7 @@ timetravel(PG_FUNCTION_ARGS)
|
||||||
relname, args[a_time_on], args[a_time_off]);
|
relname, args[a_time_on], args[a_time_off]);
|
||||||
}
|
}
|
||||||
if (oldtimeoff != NOEND_ABSTIME)
|
if (oldtimeoff != NOEND_ABSTIME)
|
||||||
{ /* current record is a deleted/updated
|
{ /* current record is a deleted/updated record */
|
||||||
* record */
|
|
||||||
pfree(relname);
|
pfree(relname);
|
||||||
return PointerGetDatum(NULL);
|
return PointerGetDatum(NULL);
|
||||||
}
|
}
|
||||||
|
@ -285,8 +284,7 @@ timetravel(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* change date column(s) */
|
/* change date column(s) */
|
||||||
cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current
|
cvals[attnum[a_time_off] - 1] = newtimeoff; /* stop_date eq current date */
|
||||||
* date */
|
|
||||||
cnulls[attnum[a_time_off] - 1] = ' ';
|
cnulls[attnum[a_time_off] - 1] = ' ';
|
||||||
|
|
||||||
if (!newtuple)
|
if (!newtuple)
|
||||||
|
@ -299,8 +297,8 @@ timetravel(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct ident string as TriggerName $ TriggeredRelationId and try
|
* Construct ident string as TriggerName $ TriggeredRelationId and try to
|
||||||
* to find prepared execution plan.
|
* find prepared execution plan.
|
||||||
*/
|
*/
|
||||||
snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
|
snprintf(ident, sizeof(ident), "%s$%u", trigger->tgname, rel->rd_id);
|
||||||
plan = find_plan(ident, &Plans, &nPlans);
|
plan = find_plan(ident, &Plans, &nPlans);
|
||||||
|
@ -339,9 +337,8 @@ timetravel(PG_FUNCTION_ARGS)
|
||||||
elog(ERROR, "timetravel (%s): SPI_prepare returned %d", relname, SPI_result);
|
elog(ERROR, "timetravel (%s): SPI_prepare returned %d", relname, SPI_result);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remember that SPI_prepare places plan in current memory context
|
* Remember that SPI_prepare places plan in current memory context -
|
||||||
* - so, we have to save plan in Top memory context for latter
|
* so, we have to save plan in Top memory context for latter use.
|
||||||
* use.
|
|
||||||
*/
|
*/
|
||||||
pplan = SPI_saveplan(pplan);
|
pplan = SPI_saveplan(pplan);
|
||||||
if (pplan == NULL)
|
if (pplan == NULL)
|
||||||
|
@ -398,8 +395,8 @@ timetravel(PG_FUNCTION_ARGS)
|
||||||
rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls);
|
rettuple = SPI_modifytuple(rel, newtuple, chnattrs, chattrs, newvals, newnulls);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SPI_copytuple allocates tmptuple in upper executor context -
|
* SPI_copytuple allocates tmptuple in upper executor context - have
|
||||||
* have to free allocation using SPI_pfree
|
* to free allocation using SPI_pfree
|
||||||
*/
|
*/
|
||||||
/* SPI_pfree(tmptuple); */
|
/* SPI_pfree(tmptuple); */
|
||||||
}
|
}
|
||||||
|
|
|
@ -184,8 +184,7 @@ normal_rand(PG_FUNCTION_ARGS)
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch to memory context appropriate for multiple function
|
* switch to memory context appropriate for multiple function calls
|
||||||
* calls
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
|
@ -196,10 +195,10 @@ normal_rand(PG_FUNCTION_ARGS)
|
||||||
fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx));
|
fctx = (normal_rand_fctx *) palloc(sizeof(normal_rand_fctx));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use fctx to keep track of upper and lower bounds from call to
|
* Use fctx to keep track of upper and lower bounds from call to call.
|
||||||
* call. It will also be used to carry over the spare value we get
|
* It will also be used to carry over the spare value we get from the
|
||||||
* from the Box-Muller algorithm so that we only actually
|
* Box-Muller algorithm so that we only actually calculate a new value
|
||||||
* calculate a new value every other call.
|
* every other call.
|
||||||
*/
|
*/
|
||||||
fctx->mean = PG_GETARG_FLOAT8(1);
|
fctx->mean = PG_GETARG_FLOAT8(1);
|
||||||
fctx->stddev = PG_GETARG_FLOAT8(2);
|
fctx->stddev = PG_GETARG_FLOAT8(2);
|
||||||
|
@ -368,8 +367,7 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
funcctx = SRF_FIRSTCALL_INIT();
|
funcctx = SRF_FIRSTCALL_INIT();
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* switch to memory context appropriate for multiple function
|
* switch to memory context appropriate for multiple function calls
|
||||||
* calls
|
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
|
@ -439,8 +437,8 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
tupdesc = CreateTupleDescCopy(tupdesc);
|
tupdesc = CreateTupleDescCopy(tupdesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check that return tupdesc is compatible with the data we got
|
* Check that return tupdesc is compatible with the data we got from
|
||||||
* from SPI, at least based on number and type of attributes
|
* SPI, at least based on number and type of attributes
|
||||||
*/
|
*/
|
||||||
if (!compatCrosstabTupleDescs(tupdesc, spi_tupdesc))
|
if (!compatCrosstabTupleDescs(tupdesc, spi_tupdesc))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -449,8 +447,8 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
"incompatible")));
|
"incompatible")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Generate attribute metadata needed later to produce tuples from
|
* Generate attribute metadata needed later to produce tuples from raw
|
||||||
* raw C strings
|
* C strings
|
||||||
*/
|
*/
|
||||||
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
attinmeta = TupleDescGetAttInMetadata(tupdesc);
|
||||||
funcctx->attinmeta = attinmeta;
|
funcctx->attinmeta = attinmeta;
|
||||||
|
@ -530,11 +528,10 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
|
rowid = SPI_getvalue(spi_tuple, spi_tupdesc, 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the first pass through the values for this
|
* If this is the first pass through the values for this rowid
|
||||||
* rowid set it, otherwise make sure it hasn't changed on
|
* set it, otherwise make sure it hasn't changed on us. Also
|
||||||
* us. Also check to see if the rowid is the same as that
|
* check to see if the rowid is the same as that of the last
|
||||||
* of the last tuple sent -- if so, skip this tuple
|
* tuple sent -- if so, skip this tuple entirely
|
||||||
* entirely
|
|
||||||
*/
|
*/
|
||||||
if (i == 0)
|
if (i == 0)
|
||||||
values[0] = pstrdup(rowid);
|
values[0] = pstrdup(rowid);
|
||||||
|
@ -550,16 +547,15 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
* Get the next category item value, which is alway
|
* Get the next category item value, which is alway
|
||||||
* attribute number three.
|
* attribute number three.
|
||||||
*
|
*
|
||||||
* Be careful to sssign the value to the array index
|
* Be careful to sssign the value to the array index based on
|
||||||
* based on which category we are presently
|
* which category we are presently processing.
|
||||||
* processing.
|
|
||||||
*/
|
*/
|
||||||
values[1 + i] = SPI_getvalue(spi_tuple, spi_tupdesc, 3);
|
values[1 + i] = SPI_getvalue(spi_tuple, spi_tupdesc, 3);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* increment the counter since we consume a row for
|
* increment the counter since we consume a row for each
|
||||||
* each category, but not for last pass because the
|
* category, but not for last pass because the API will do
|
||||||
* API will do that for us
|
* that for us
|
||||||
*/
|
*/
|
||||||
if (i < (num_categories - 1))
|
if (i < (num_categories - 1))
|
||||||
call_cntr = ++funcctx->call_cntr;
|
call_cntr = ++funcctx->call_cntr;
|
||||||
|
@ -567,9 +563,9 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We'll fill in NULLs for the missing values, but we
|
* We'll fill in NULLs for the missing values, but we need
|
||||||
* need to decrement the counter since this sql result
|
* to decrement the counter since this sql result row
|
||||||
* row doesn't belong to the current output tuple.
|
* doesn't belong to the current output tuple.
|
||||||
*/
|
*/
|
||||||
call_cntr = --funcctx->call_cntr;
|
call_cntr = --funcctx->call_cntr;
|
||||||
break;
|
break;
|
||||||
|
@ -584,8 +580,8 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
if (values[0] != NULL)
|
if (values[0] != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* switch to memory context appropriate for multiple
|
* switch to memory context appropriate for multiple function
|
||||||
* function calls
|
* calls
|
||||||
*/
|
*/
|
||||||
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
|
||||||
|
|
||||||
|
@ -612,8 +608,8 @@ crosstab(PG_FUNCTION_ARGS)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Skipping this tuple entirely, but we need to advance
|
* Skipping this tuple entirely, but we need to advance the
|
||||||
* the counter like the API would if we had returned one.
|
* counter like the API would if we had returned one.
|
||||||
*/
|
*/
|
||||||
call_cntr = ++funcctx->call_cntr;
|
call_cntr = ++funcctx->call_cntr;
|
||||||
|
|
||||||
|
@ -730,10 +726,10 @@ crosstab_hash(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
||||||
* tuples are in our tuplestore and passed back through
|
* tuples are in our tuplestore and passed back through rsinfo->setResult.
|
||||||
* rsinfo->setResult. rsinfo->setDesc is set to the tuple description
|
* rsinfo->setDesc is set to the tuple description that we actually used
|
||||||
* that we actually used to build our tuples with, so the caller can
|
* to build our tuples with, so the caller can verify we did what it was
|
||||||
* verify we did what it was expecting.
|
* expecting.
|
||||||
*/
|
*/
|
||||||
rsinfo->setDesc = tupdesc;
|
rsinfo->setDesc = tupdesc;
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
@ -758,8 +754,8 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
|
||||||
ctl.entrysize = sizeof(crosstab_HashEnt);
|
ctl.entrysize = sizeof(crosstab_HashEnt);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* use INIT_CATS, defined above as a guess of how many hash table
|
* use INIT_CATS, defined above as a guess of how many hash table entries
|
||||||
* entries to create, initially
|
* to create, initially
|
||||||
*/
|
*/
|
||||||
crosstab_HashTable = hash_create("crosstab hash", INIT_CATS, &ctl, HASH_ELEM);
|
crosstab_HashTable = hash_create("crosstab hash", INIT_CATS, &ctl, HASH_ELEM);
|
||||||
|
|
||||||
|
@ -780,8 +776,8 @@ load_categories_hash(char *cats_sql, MemoryContext per_query_ctx)
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The provided categories SQL query must always return one
|
* The provided categories SQL query must always return one column:
|
||||||
* column: category - the label or identifier for each column
|
* category - the label or identifier for each column
|
||||||
*/
|
*/
|
||||||
if (spi_tupdesc->natts != 1)
|
if (spi_tupdesc->natts != 1)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -872,19 +868,17 @@ get_crosstab_tuplestore(char *sql,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The provided SQL query must always return at least three
|
* The provided SQL query must always return at least three columns:
|
||||||
* columns:
|
|
||||||
*
|
*
|
||||||
* 1. rowname the label for each row - column 1 in the final result
|
* 1. rowname the label for each row - column 1 in the final result 2.
|
||||||
* 2. category the label for each value-column in the final
|
* category the label for each value-column in the final result 3.
|
||||||
* result 3. value the values used to populate the
|
* value the values used to populate the value-columns
|
||||||
* value-columns
|
|
||||||
*
|
*
|
||||||
* If there are more than three columns, the last two are taken as
|
* If there are more than three columns, the last two are taken as
|
||||||
* "category" and "values". The first column is taken as
|
* "category" and "values". The first column is taken as "rowname".
|
||||||
* "rowname". Additional columns (2 thru N-2) are assumed the same
|
* Additional columns (2 thru N-2) are assumed the same for the same
|
||||||
* for the same "rowname", and are copied into the result tuple
|
* "rowname", and are copied into the result tuple from the first time
|
||||||
* from the first time we encounter a particular rowname.
|
* we encounter a particular rowname.
|
||||||
*/
|
*/
|
||||||
if (ncols < 3)
|
if (ncols < 3)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -933,14 +927,13 @@ get_crosstab_tuplestore(char *sql,
|
||||||
if ((lastrowid == NULL) || (strcmp(rowid, lastrowid) != 0))
|
if ((lastrowid == NULL) || (strcmp(rowid, lastrowid) != 0))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* a new row means we need to flush the old one first,
|
* a new row means we need to flush the old one first, unless
|
||||||
* unless we're on the very first row
|
* we're on the very first row
|
||||||
*/
|
*/
|
||||||
if (lastrowid != NULL)
|
if (lastrowid != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* switch to appropriate context while storing the
|
* switch to appropriate context while storing the tuple
|
||||||
* tuple
|
|
||||||
*/
|
*/
|
||||||
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
|
SPIcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||||
|
|
||||||
|
@ -1103,10 +1096,10 @@ connectby_text(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
||||||
* tuples are in our tuplestore and passed back through
|
* tuples are in our tuplestore and passed back through rsinfo->setResult.
|
||||||
* rsinfo->setResult. rsinfo->setDesc is set to the tuple description
|
* rsinfo->setDesc is set to the tuple description that we actually used
|
||||||
* that we actually used to build our tuples with, so the caller can
|
* to build our tuples with, so the caller can verify we did what it was
|
||||||
* verify we did what it was expecting.
|
* expecting.
|
||||||
*/
|
*/
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
}
|
}
|
||||||
|
@ -1182,10 +1175,10 @@ connectby_text_serial(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
||||||
* tuples are in our tuplestore and passed back through
|
* tuples are in our tuplestore and passed back through rsinfo->setResult.
|
||||||
* rsinfo->setResult. rsinfo->setDesc is set to the tuple description
|
* rsinfo->setDesc is set to the tuple description that we actually used
|
||||||
* that we actually used to build our tuples with, so the caller can
|
* to build our tuples with, so the caller can verify we did what it was
|
||||||
* verify we did what it was expecting.
|
* expecting.
|
||||||
*/
|
*/
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
}
|
}
|
||||||
|
@ -1382,8 +1375,8 @@ build_tuplestore_recursively(char *key_fld,
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Check that return tupdesc is compatible with the one we got
|
* Check that return tupdesc is compatible with the one we got
|
||||||
* from the query, but only at level 0 -- no need to check
|
* from the query, but only at level 0 -- no need to check more
|
||||||
* more than once
|
* than once
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (!compatConnectbyTupleDescs(tupdesc, spi_tupdesc))
|
if (!compatConnectbyTupleDescs(tupdesc, spi_tupdesc))
|
||||||
|
@ -1605,9 +1598,9 @@ compatCrosstabTupleDescs(TupleDesc ret_tupdesc, TupleDesc sql_tupdesc)
|
||||||
"return rowid datatype.")));
|
"return rowid datatype.")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* - attribute [1] of the sql tuple is the category; no need to check
|
* - attribute [1] of the sql tuple is the category; no need to check it -
|
||||||
* it - attribute [2] of the sql tuple should match attributes [1] to
|
* attribute [2] of the sql tuple should match attributes [1] to [natts]
|
||||||
* [natts] of the return tuple
|
* of the return tuple
|
||||||
*/
|
*/
|
||||||
sql_attr = sql_tupdesc->attrs[2];
|
sql_attr = sql_tupdesc->attrs[2];
|
||||||
for (i = 1; i < ret_tupdesc->natts; i++)
|
for (i = 1; i < ret_tupdesc->natts; i++)
|
||||||
|
|
|
@ -39,18 +39,14 @@ typedef struct
|
||||||
void parse_cfgdict(text *in, Map ** m);
|
void parse_cfgdict(text *in, Map ** m);
|
||||||
|
|
||||||
/* return struct for any lexize function */
|
/* return struct for any lexize function */
|
||||||
typedef struct {
|
typedef struct
|
||||||
/* number of variant of split word , for example
|
{
|
||||||
Word 'fotballklubber' (norwegian) has two varian to split:
|
/*
|
||||||
( fotball, klubb ) and ( fot, ball, klubb ). So, dictionary
|
* number of variant of split word , for example Word 'fotballklubber'
|
||||||
should return:
|
* (norwegian) has two varian to split: ( fotball, klubb ) and ( fot,
|
||||||
nvariant lexeme
|
* ball, klubb ). So, dictionary should return: nvariant lexeme 1
|
||||||
1 fotball
|
* fotball 1 klubb 2 fot 2 ball 2 klubb
|
||||||
1 klubb
|
*
|
||||||
2 fot
|
|
||||||
2 ball
|
|
||||||
2 klubb
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
uint16 nvariant;
|
uint16 nvariant;
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,10 @@ gtsvector_out(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
if (ISARRKEY(key))
|
if (ISARRKEY(key))
|
||||||
sprintf(outbuf, ARROUTSTR, (int) ARRNELEM(key));
|
sprintf(outbuf, ARROUTSTR, (int) ARRNELEM(key));
|
||||||
else {
|
else
|
||||||
|
{
|
||||||
int cnttrue = (ISALLTRUE(key)) ? SIGLENBIT : sizebitvec(GETSIGN(key));
|
int cnttrue = (ISALLTRUE(key)) ? SIGLENBIT : sizebitvec(GETSIGN(key));
|
||||||
|
|
||||||
sprintf(outbuf, SINGOUTSTR, cnttrue, (int) SIGLENBIT - cnttrue);
|
sprintf(outbuf, SINGOUTSTR, cnttrue, (int) SIGLENBIT - cnttrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,8 +167,8 @@ gtsvector_compress(PG_FUNCTION_ARGS)
|
||||||
if (len != val->size)
|
if (len != val->size)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* there is a collision of hash-function; len is always less
|
* there is a collision of hash-function; len is always less than
|
||||||
* than val->size
|
* val->size
|
||||||
*/
|
*/
|
||||||
len = CALCGTSIZE(ARRKEY, len);
|
len = CALCGTSIZE(ARRKEY, len);
|
||||||
res = (GISTTYPE *) repalloc((void *) res, len);
|
res = (GISTTYPE *) repalloc((void *) res, len);
|
||||||
|
|
|
@ -10,8 +10,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define BITBYTE 8
|
#define BITBYTE 8
|
||||||
#define SIGLENINT 63 /* >121 => key will toast, so it will not
|
#define SIGLENINT 63 /* >121 => key will toast, so it will not work
|
||||||
* work !!! */
|
* !!! */
|
||||||
#define SIGLEN ( sizeof(int4) * SIGLENINT )
|
#define SIGLEN ( sizeof(int4) * SIGLENINT )
|
||||||
#define SIGLENBIT (SIGLEN * BITBYTE)
|
#define SIGLENBIT (SIGLEN * BITBYTE)
|
||||||
|
|
||||||
|
|
|
@ -489,8 +489,8 @@ mkSPNode(IspellDict * Conf, int low, int high, int level)
|
||||||
if (data->isword && data->affix != Conf->Spell[i].p.d.affix)
|
if (data->isword && data->affix != Conf->Spell[i].p.d.affix)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* fprintf(stderr,"Word already exists: %s (affixes:
|
* fprintf(stderr,"Word already exists: %s (affixes: '%s'
|
||||||
* '%s' and '%s')\n", Conf->Spell[i].word,
|
* and '%s')\n", Conf->Spell[i].word,
|
||||||
* Conf->AffixData[data->affix],
|
* Conf->AffixData[data->affix],
|
||||||
* Conf->AffixData[Conf->Spell[i].p.d.affix] );
|
* Conf->AffixData[Conf->Spell[i].p.d.affix] );
|
||||||
*/
|
*/
|
||||||
|
@ -807,6 +807,7 @@ CheckAffix(const char *word, size_t len, AFFIX * Affix, char flagflags, char *ne
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
char regerrstr[ERRSTRSIZE];
|
char regerrstr[ERRSTRSIZE];
|
||||||
|
|
||||||
pg_regerror(err, &(Affix->reg.regex), regerrstr, ERRSTRSIZE);
|
pg_regerror(err, &(Affix->reg.regex), regerrstr, ERRSTRSIZE);
|
||||||
elog(ERROR, "Regex error in '%s': %s", Affix->mask, regerrstr);
|
elog(ERROR, "Regex error in '%s': %s", Affix->mask, regerrstr);
|
||||||
}
|
}
|
||||||
|
@ -1037,8 +1038,7 @@ SplitToVariants(IspellDict * Conf, SPNode * snode, SplitVar * orig, char *word,
|
||||||
while (level > startpos && (lenaff = CheckCompoundAffixes(&caff, word + level, wordlen - level)) > 0)
|
while (level > startpos && (lenaff = CheckCompoundAffixes(&caff, word + level, wordlen - level)) > 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* there is one of compound suffixes, so check word for
|
* there is one of compound suffixes, so check word for existings
|
||||||
* existings
|
|
||||||
*/
|
*/
|
||||||
char buf[MAXNORMLEN];
|
char buf[MAXNORMLEN];
|
||||||
char **subres;
|
char **subres;
|
||||||
|
@ -1128,13 +1128,17 @@ TSLexeme *
|
||||||
NINormalizeWord(IspellDict * Conf, char *word)
|
NINormalizeWord(IspellDict * Conf, char *word)
|
||||||
{
|
{
|
||||||
char **res = NormalizeSubWord(Conf, word, 0);
|
char **res = NormalizeSubWord(Conf, word, 0);
|
||||||
TSLexeme *lcur=NULL, *lres=NULL;
|
TSLexeme *lcur = NULL,
|
||||||
|
*lres = NULL;
|
||||||
uint16 NVariant = 1;
|
uint16 NVariant = 1;
|
||||||
|
|
||||||
if (res) {
|
if (res)
|
||||||
|
{
|
||||||
char **ptr = res;
|
char **ptr = res;
|
||||||
|
|
||||||
lcur = lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
|
lcur = lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
|
||||||
while(*ptr) {
|
while (*ptr)
|
||||||
|
{
|
||||||
lcur->lexeme = *ptr;
|
lcur->lexeme = *ptr;
|
||||||
lcur->flags = 0;
|
lcur->flags = 0;
|
||||||
lcur->nvariant = NVariant++;
|
lcur->nvariant = NVariant++;
|
||||||
|
@ -1165,8 +1169,10 @@ NINormalizeWord(IspellDict * Conf, char *word)
|
||||||
if (!lcur)
|
if (!lcur)
|
||||||
lcur = lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
|
lcur = lres = (TSLexeme *) palloc(MAX_NORM * sizeof(TSLexeme));
|
||||||
|
|
||||||
while(*subptr) {
|
while (*subptr)
|
||||||
for(i=0;i<var->nstem-1;i++) {
|
{
|
||||||
|
for (i = 0; i < var->nstem - 1; i++)
|
||||||
|
{
|
||||||
lcur->lexeme = (subptr == subres) ? var->stem[i] : pstrdup(var->stem[i]);
|
lcur->lexeme = (subptr == subres) ? var->stem[i] : pstrdup(var->stem[i]);
|
||||||
lcur->flags = 0;
|
lcur->flags = 0;
|
||||||
lcur->nvariant = NVariant;
|
lcur->nvariant = NVariant;
|
||||||
|
|
|
@ -265,7 +265,11 @@ pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 we
|
||||||
{
|
{
|
||||||
int4 count = 0;
|
int4 count = 0;
|
||||||
PRSTEXT prs;
|
PRSTEXT prs;
|
||||||
uint32 variant, pos, cntvar=0, cntpos=0, cnt=0;
|
uint32 variant,
|
||||||
|
pos,
|
||||||
|
cntvar = 0,
|
||||||
|
cntpos = 0,
|
||||||
|
cnt = 0;
|
||||||
|
|
||||||
prs.lenwords = 32;
|
prs.lenwords = 32;
|
||||||
prs.curwords = 0;
|
prs.curwords = 0;
|
||||||
|
@ -274,16 +278,20 @@ pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 we
|
||||||
|
|
||||||
parsetext_v2(findcfg(state->cfg_id), &prs, strval, lenval);
|
parsetext_v2(findcfg(state->cfg_id), &prs, strval, lenval);
|
||||||
|
|
||||||
if ( prs.curwords>0 ) {
|
if (prs.curwords > 0)
|
||||||
|
{
|
||||||
|
|
||||||
while (count < prs.curwords) {
|
while (count < prs.curwords)
|
||||||
|
{
|
||||||
pos = prs.words[count].pos.pos;
|
pos = prs.words[count].pos.pos;
|
||||||
cntvar = 0;
|
cntvar = 0;
|
||||||
while(count < prs.curwords && pos==prs.words[count].pos.pos) {
|
while (count < prs.curwords && pos == prs.words[count].pos.pos)
|
||||||
|
{
|
||||||
variant = prs.words[count].nvariant;
|
variant = prs.words[count].nvariant;
|
||||||
|
|
||||||
cnt = 0;
|
cnt = 0;
|
||||||
while(count < prs.curwords && pos==prs.words[count].pos.pos && variant==prs.words[count].nvariant) {
|
while (count < prs.curwords && pos == prs.words[count].pos.pos && variant == prs.words[count].nvariant)
|
||||||
|
{
|
||||||
|
|
||||||
pushval_asis(state, VAL, prs.words[count].word, prs.words[count].len, weight);
|
pushval_asis(state, VAL, prs.words[count].word, prs.words[count].len, weight);
|
||||||
pfree(prs.words[count].word);
|
pfree(prs.words[count].word);
|
||||||
|
@ -306,7 +314,8 @@ pushval_morph(QPRS_STATE * state, int typeval, char *strval, int lenval, int2 we
|
||||||
|
|
||||||
pfree(prs.words);
|
pfree(prs.words);
|
||||||
|
|
||||||
} else
|
}
|
||||||
|
else
|
||||||
pushval_asis(state, VALSTOP, NULL, 0, 0);
|
pushval_asis(state, VALSTOP, NULL, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,7 @@ static float weights[] = {0.1, 0.2, 0.4, 1.0};
|
||||||
|
|
||||||
static float calc_rank_or(float *w, tsvector * t, QUERYTYPE * q);
|
static float calc_rank_or(float *w, tsvector * t, QUERYTYPE * q);
|
||||||
static float calc_rank_and(float *w, tsvector * t, QUERYTYPE * q);
|
static float calc_rank_and(float *w, tsvector * t, QUERYTYPE * q);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns a weight of a word collocation
|
* Returns a weight of a word collocation
|
||||||
*/
|
*/
|
||||||
|
@ -118,7 +119,8 @@ find_wordentry(tsvector * t, QUERYTYPE * q, ITEM * item)
|
||||||
static char *SortAndUniqOperand = NULL;
|
static char *SortAndUniqOperand = NULL;
|
||||||
|
|
||||||
static int
|
static int
|
||||||
compareITEM( const void * a, const void * b ) {
|
compareITEM(const void *a, const void *b)
|
||||||
|
{
|
||||||
if ((*(ITEM **) a)->length == (*(ITEM **) b)->length)
|
if ((*(ITEM **) a)->length == (*(ITEM **) b)->length)
|
||||||
return strncmp(SortAndUniqOperand + (*(ITEM **) a)->distance,
|
return strncmp(SortAndUniqOperand + (*(ITEM **) a)->distance,
|
||||||
SortAndUniqOperand + (*(ITEM **) b)->distance,
|
SortAndUniqOperand + (*(ITEM **) b)->distance,
|
||||||
|
@ -128,13 +130,18 @@ compareITEM( const void * a, const void * b ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static ITEM **
|
static ITEM **
|
||||||
SortAndUniqItems( char *operand, ITEM *item, int *size ) {
|
SortAndUniqItems(char *operand, ITEM * item, int *size)
|
||||||
ITEM **res, **ptr, **prevptr;
|
{
|
||||||
|
ITEM **res,
|
||||||
|
**ptr,
|
||||||
|
**prevptr;
|
||||||
|
|
||||||
ptr = res = (ITEM **) palloc(sizeof(ITEM *) * *size);
|
ptr = res = (ITEM **) palloc(sizeof(ITEM *) * *size);
|
||||||
|
|
||||||
while( (*size)-- ) {
|
while ((*size)--)
|
||||||
if ( item->type == VAL ) {
|
{
|
||||||
|
if (item->type == VAL)
|
||||||
|
{
|
||||||
*ptr = item;
|
*ptr = item;
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
@ -151,8 +158,10 @@ SortAndUniqItems( char *operand, ITEM *item, int *size ) {
|
||||||
ptr = res + 1;
|
ptr = res + 1;
|
||||||
prevptr = res;
|
prevptr = res;
|
||||||
|
|
||||||
while( ptr - res < *size ) {
|
while (ptr - res < *size)
|
||||||
if ( compareITEM( (void*) ptr, (void*) prevptr ) != 0 ) {
|
{
|
||||||
|
if (compareITEM((void *) ptr, (void *) prevptr) != 0)
|
||||||
|
{
|
||||||
prevptr++;
|
prevptr++;
|
||||||
*prevptr = *ptr;
|
*prevptr = *ptr;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +196,8 @@ calc_rank_and(float *w, tsvector * t, QUERYTYPE * q)
|
||||||
int size = q->size;
|
int size = q->size;
|
||||||
|
|
||||||
item = SortAndUniqItems(GETOPERAND(q), GETQUERY(q), &size);
|
item = SortAndUniqItems(GETOPERAND(q), GETQUERY(q), &size);
|
||||||
if ( size < 2 ) {
|
if (size < 2)
|
||||||
|
{
|
||||||
pfree(item);
|
pfree(item);
|
||||||
return calc_rank_or(w, t, q);
|
return calc_rank_or(w, t, q);
|
||||||
}
|
}
|
||||||
|
@ -308,7 +318,8 @@ calc_rank(float *w, tsvector * t, QUERYTYPE * q, int4 method)
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
len = cnt_length(t);
|
len = cnt_length(t);
|
||||||
if ( len > 0 ) res /= (float)len;
|
if (len > 0)
|
||||||
|
res /= (float) len;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* internal error */
|
/* internal error */
|
||||||
|
@ -500,8 +511,7 @@ Cover(DocRepresentation * doc, int len, QUERYTYPE * query, int *pos, int *p, int
|
||||||
if (TS_execute(GETQUERY(query), &ch, false, checkcondition_DR))
|
if (TS_execute(GETQUERY(query), &ch, false, checkcondition_DR))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* elog(NOTICE,"OP:%d NP:%d P:%d Q:%d", *pos, lastpos, *p,
|
* elog(NOTICE,"OP:%d NP:%d P:%d Q:%d", *pos, lastpos, *p, *q);
|
||||||
* *q);
|
|
||||||
*/
|
*/
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -615,7 +625,8 @@ rank_cd(PG_FUNCTION_ARGS)
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
len = cnt_length(txt);
|
len = cnt_length(txt);
|
||||||
if ( len > 0 ) res /= (float)len;
|
if (len > 0)
|
||||||
|
res /= (float) len;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* internal error */
|
/* internal error */
|
||||||
|
|
|
@ -2,22 +2,29 @@
|
||||||
#include <stdlib.h> /* for calloc, free */
|
#include <stdlib.h> /* for calloc, free */
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
|
|
||||||
extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size)
|
extern struct SN_env *
|
||||||
|
SN_create_env(int S_size, int I_size, int B_size)
|
||||||
{
|
{
|
||||||
struct SN_env *z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
|
struct SN_env *z = (struct SN_env *) calloc(1, sizeof(struct SN_env));
|
||||||
if (z == NULL) return NULL;
|
|
||||||
|
if (z == NULL)
|
||||||
|
return NULL;
|
||||||
z->p = create_s();
|
z->p = create_s();
|
||||||
if (z->p == NULL) goto error;
|
if (z->p == NULL)
|
||||||
|
goto error;
|
||||||
if (S_size)
|
if (S_size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
z->S = (symbol * *) calloc(S_size, sizeof(symbol *));
|
z->S = (symbol * *) calloc(S_size, sizeof(symbol *));
|
||||||
if (z->S == NULL) goto error;
|
if (z->S == NULL)
|
||||||
|
goto error;
|
||||||
|
|
||||||
for (i = 0; i < S_size; i++)
|
for (i = 0; i < S_size; i++)
|
||||||
{
|
{
|
||||||
z->S[i] = create_s();
|
z->S[i] = create_s();
|
||||||
if (z->S[i] == NULL) goto error;
|
if (z->S[i] == NULL)
|
||||||
|
goto error;
|
||||||
}
|
}
|
||||||
z->S_size = S_size;
|
z->S_size = S_size;
|
||||||
}
|
}
|
||||||
|
@ -25,14 +32,16 @@ extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size)
|
||||||
if (I_size)
|
if (I_size)
|
||||||
{
|
{
|
||||||
z->I = (int *) calloc(I_size, sizeof(int));
|
z->I = (int *) calloc(I_size, sizeof(int));
|
||||||
if (z->I == NULL) goto error;
|
if (z->I == NULL)
|
||||||
|
goto error;
|
||||||
z->I_size = I_size;
|
z->I_size = I_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (B_size)
|
if (B_size)
|
||||||
{
|
{
|
||||||
z->B = (symbol *) calloc(B_size, sizeof(symbol));
|
z->B = (symbol *) calloc(B_size, sizeof(symbol));
|
||||||
if (z->B == NULL) goto error;
|
if (z->B == NULL)
|
||||||
|
goto error;
|
||||||
z->B_size = B_size;
|
z->B_size = B_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,28 +51,35 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void SN_close_env(struct SN_env * z)
|
extern void
|
||||||
|
SN_close_env(struct SN_env * z)
|
||||||
{
|
{
|
||||||
if (z == NULL) return;
|
if (z == NULL)
|
||||||
|
return;
|
||||||
if (z->S_size)
|
if (z->S_size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < z->S_size; i++)
|
for (i = 0; i < z->S_size; i++)
|
||||||
{
|
{
|
||||||
lose_s(z->S[i]);
|
lose_s(z->S[i]);
|
||||||
}
|
}
|
||||||
free(z->S);
|
free(z->S);
|
||||||
}
|
}
|
||||||
if (z->I_size) free(z->I);
|
if (z->I_size)
|
||||||
if (z->B_size) free(z->B);
|
free(z->I);
|
||||||
if (z->p) lose_s(z->p);
|
if (z->B_size)
|
||||||
|
free(z->B);
|
||||||
|
if (z->p)
|
||||||
|
lose_s(z->p);
|
||||||
free(z);
|
free(z);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int SN_set_current(struct SN_env * z, int size, const symbol * s)
|
extern int
|
||||||
|
SN_set_current(struct SN_env * z, int size, const symbol * s)
|
||||||
{
|
{
|
||||||
int err = replace_s(z, 0, z->l, size, s, NULL);
|
int err = replace_s(z, 0, z->l, size, s, NULL);
|
||||||
|
|
||||||
z->c = 0;
|
z->c = 0;
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,18 @@ typedef unsigned char symbol;
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct SN_env {
|
struct SN_env
|
||||||
|
{
|
||||||
symbol *p;
|
symbol *p;
|
||||||
int c; int a; int l; int lb; int bra; int ket;
|
int c;
|
||||||
int S_size; int I_size; int B_size;
|
int a;
|
||||||
|
int l;
|
||||||
|
int lb;
|
||||||
|
int bra;
|
||||||
|
int ket;
|
||||||
|
int S_size;
|
||||||
|
int I_size;
|
||||||
|
int B_size;
|
||||||
symbol **S;
|
symbol **S;
|
||||||
int *I;
|
int *I;
|
||||||
symbol *B;
|
symbol *B;
|
||||||
|
@ -24,4 +32,3 @@ extern struct SN_env * SN_create_env(int S_size, int I_size, int B_size);
|
||||||
extern void SN_close_env(struct SN_env * z);
|
extern void SN_close_env(struct SN_env * z);
|
||||||
|
|
||||||
extern int SN_set_current(struct SN_env * z, int size, const symbol * s);
|
extern int SN_set_current(struct SN_env * z, int size, const symbol * s);
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -2,7 +2,8 @@
|
||||||
/* This file was generated automatically by the Snowball to ANSI C compiler */
|
/* This file was generated automatically by the Snowball to ANSI C compiler */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct SN_env *english_ISO_8859_1_create_env(void);
|
extern struct SN_env *english_ISO_8859_1_create_env(void);
|
||||||
|
@ -12,5 +13,5 @@ extern int english_ISO_8859_1_stem(struct SN_env * z);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
#define CAPACITY(p) ((int *)(p))[-2]
|
#define CAPACITY(p) ((int *)(p))[-2]
|
||||||
|
|
||||||
struct among
|
struct among
|
||||||
{ int s_size; /* number of chars in string */
|
{
|
||||||
|
int s_size; /* number of chars in string */
|
||||||
symbol *s; /* search string */
|
symbol *s; /* search string */
|
||||||
int substring_i; /* index to longest matching substring */
|
int substring_i; /* index to longest matching substring */
|
||||||
int result; /* result of the lookup */
|
int result; /* result of the lookup */
|
||||||
|
@ -55,4 +56,3 @@ extern symbol * slice_to(struct SN_env * z, symbol * p);
|
||||||
extern symbol *assign_to(struct SN_env * z, symbol * p);
|
extern symbol *assign_to(struct SN_env * z, symbol * p);
|
||||||
|
|
||||||
extern void debug(struct SN_env * z, int number, int line_count);
|
extern void debug(struct SN_env * z, int number, int line_count);
|
||||||
|
|
||||||
|
|
|
@ -337,37 +337,53 @@ static symbol s_7[] = { 0xCE };
|
||||||
static symbol s_8[] = {0xCE};
|
static symbol s_8[] = {0xCE};
|
||||||
static symbol s_9[] = {0xC9};
|
static symbol s_9[] = {0xC9};
|
||||||
|
|
||||||
static int r_mark_regions(struct SN_env * z) {
|
static int
|
||||||
|
r_mark_regions(struct SN_env * z)
|
||||||
|
{
|
||||||
z->I[0] = z->l;
|
z->I[0] = z->l;
|
||||||
z->I[1] = z->l;
|
z->I[1] = z->l;
|
||||||
{ int c = z->c; /* do, line 63 */
|
{
|
||||||
while(1) { /* gopast, line 64 */
|
int c = z->c; /* do, line 63 */
|
||||||
if (!(in_grouping(z, g_v, 192, 220))) goto lab1;
|
|
||||||
|
while (1)
|
||||||
|
{ /* gopast, line 64 */
|
||||||
|
if (!(in_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab1;
|
||||||
break;
|
break;
|
||||||
lab1:
|
lab1:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++; /* gopast, line 64 */
|
z->c++; /* gopast, line 64 */
|
||||||
}
|
}
|
||||||
z->I[0] = z->c; /* setmark pV, line 64 */
|
z->I[0] = z->c; /* setmark pV, line 64 */
|
||||||
while(1) { /* gopast, line 64 */
|
while (1)
|
||||||
if (!(out_grouping(z, g_v, 192, 220))) goto lab2;
|
{ /* gopast, line 64 */
|
||||||
|
if (!(out_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab2;
|
||||||
break;
|
break;
|
||||||
lab2:
|
lab2:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++; /* gopast, line 64 */
|
z->c++; /* gopast, line 64 */
|
||||||
}
|
}
|
||||||
while(1) { /* gopast, line 65 */
|
while (1)
|
||||||
if (!(in_grouping(z, g_v, 192, 220))) goto lab3;
|
{ /* gopast, line 65 */
|
||||||
|
if (!(in_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab3;
|
||||||
break;
|
break;
|
||||||
lab3:
|
lab3:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++; /* gopast, line 65 */
|
z->c++; /* gopast, line 65 */
|
||||||
}
|
}
|
||||||
while(1) { /* gopast, line 65 */
|
while (1)
|
||||||
if (!(out_grouping(z, g_v, 192, 220))) goto lab4;
|
{ /* gopast, line 65 */
|
||||||
|
if (!(out_grouping(z, g_v, 192, 220)))
|
||||||
|
goto lab4;
|
||||||
break;
|
break;
|
||||||
lab4:
|
lab4:
|
||||||
if (z->c >= z->l) goto lab0;
|
if (z->c >= z->l)
|
||||||
|
goto lab0;
|
||||||
z->c++; /* gopast, line 65 */
|
z->c++; /* gopast, line 65 */
|
||||||
}
|
}
|
||||||
z->I[1] = z->c; /* setmark p2, line 65 */
|
z->I[1] = z->c; /* setmark p2, line 65 */
|
||||||
|
@ -377,92 +393,154 @@ static int r_mark_regions(struct SN_env * z) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_R2(struct SN_env * z) {
|
static int
|
||||||
if (!(z->I[1] <= z->c)) return 0;
|
r_R2(struct SN_env * z)
|
||||||
|
{
|
||||||
|
if (!(z->I[1] <= z->c))
|
||||||
|
return 0;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_perfective_gerund(struct SN_env * z) {
|
static int
|
||||||
|
r_perfective_gerund(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 74 */
|
z->ket = z->c; /* [, line 74 */
|
||||||
among_var = find_among_b(z, a_0, 9); /* substring, line 74 */
|
among_var = find_among_b(z, a_0, 9); /* substring, line 74 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 74 */
|
z->bra = z->c; /* ], line 74 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; (void) m; /* or, line 78 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_0))) goto lab1;
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m; /* or, line 78 */
|
||||||
|
if (!(eq_s_b(z, 1, s_0)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_1))) return 0;
|
if (!(eq_s_b(z, 1, s_1)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 78 */
|
ret = slice_del(z); /* delete, line 78 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 85 */
|
ret = slice_del(z); /* delete, line 85 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_adjective(struct SN_env * z) {
|
static int
|
||||||
|
r_adjective(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 90 */
|
z->ket = z->c; /* [, line 90 */
|
||||||
among_var = find_among_b(z, a_1, 26); /* substring, line 90 */
|
among_var = find_among_b(z, a_1, 26); /* substring, line 90 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 90 */
|
z->bra = z->c; /* ], line 90 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 99 */
|
ret = slice_del(z); /* delete, line 99 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_adjectival(struct SN_env * z) {
|
static int
|
||||||
|
r_adjectival(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
{ int ret = r_adjective(z);
|
|
||||||
if (ret == 0) return 0; /* call adjective, line 104 */
|
{
|
||||||
if (ret < 0) return ret;
|
int ret = r_adjective(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0; /* call adjective, line 104 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; (void) m; /* try, line 111 */
|
{
|
||||||
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m; /* try, line 111 */
|
||||||
z->ket = z->c; /* [, line 112 */
|
z->ket = z->c; /* [, line 112 */
|
||||||
among_var = find_among_b(z, a_2, 8); /* substring, line 112 */
|
among_var = find_among_b(z, a_2, 8); /* substring, line 112 */
|
||||||
if (!(among_var)) { z->c = z->l - m; goto lab0; }
|
if (!(among_var))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab0;
|
||||||
|
}
|
||||||
z->bra = z->c; /* ], line 112 */
|
z->bra = z->c; /* ], line 112 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: { z->c = z->l - m; goto lab0; }
|
{
|
||||||
|
case 0:
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab0;
|
||||||
|
}
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; (void) m; /* or, line 117 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_2))) goto lab2;
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m; /* or, line 117 */
|
||||||
|
if (!(eq_s_b(z, 1, s_2)))
|
||||||
|
goto lab2;
|
||||||
goto lab1;
|
goto lab1;
|
||||||
lab2:
|
lab2:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_3))) { z->c = z->l - m; goto lab0; }
|
if (!(eq_s_b(z, 1, s_3)))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
lab1:
|
lab1:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 117 */
|
ret = slice_del(z); /* delete, line 117 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 124 */
|
ret = slice_del(z); /* delete, line 124 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -472,187 +550,305 @@ static int r_adjectival(struct SN_env * z) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_reflexive(struct SN_env * z) {
|
static int
|
||||||
|
r_reflexive(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 131 */
|
z->ket = z->c; /* [, line 131 */
|
||||||
among_var = find_among_b(z, a_3, 2); /* substring, line 131 */
|
among_var = find_among_b(z, a_3, 2); /* substring, line 131 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 131 */
|
z->bra = z->c; /* ], line 131 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 134 */
|
ret = slice_del(z); /* delete, line 134 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_verb(struct SN_env * z) {
|
static int
|
||||||
|
r_verb(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 139 */
|
z->ket = z->c; /* [, line 139 */
|
||||||
among_var = find_among_b(z, a_4, 46); /* substring, line 139 */
|
among_var = find_among_b(z, a_4, 46); /* substring, line 139 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 139 */
|
z->bra = z->c; /* ], line 139 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int m = z->l - z->c; (void) m; /* or, line 145 */
|
{
|
||||||
if (!(eq_s_b(z, 1, s_4))) goto lab1;
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m; /* or, line 145 */
|
||||||
|
if (!(eq_s_b(z, 1, s_4)))
|
||||||
|
goto lab1;
|
||||||
goto lab0;
|
goto lab0;
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
if (!(eq_s_b(z, 1, s_5))) return 0;
|
if (!(eq_s_b(z, 1, s_5)))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 145 */
|
ret = slice_del(z); /* delete, line 145 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 153 */
|
ret = slice_del(z); /* delete, line 153 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_noun(struct SN_env * z) {
|
static int
|
||||||
|
r_noun(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 162 */
|
z->ket = z->c; /* [, line 162 */
|
||||||
among_var = find_among_b(z, a_5, 36); /* substring, line 162 */
|
among_var = find_among_b(z, a_5, 36); /* substring, line 162 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 162 */
|
z->bra = z->c; /* ], line 162 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 169 */
|
ret = slice_del(z); /* delete, line 169 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_derivational(struct SN_env * z) {
|
static int
|
||||||
|
r_derivational(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 178 */
|
z->ket = z->c; /* [, line 178 */
|
||||||
among_var = find_among_b(z, a_6, 2); /* substring, line 178 */
|
among_var = find_among_b(z, a_6, 2); /* substring, line 178 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 178 */
|
z->bra = z->c; /* ], line 178 */
|
||||||
{ int ret = r_R2(z);
|
{
|
||||||
if (ret == 0) return 0; /* call R2, line 178 */
|
int ret = r_R2(z);
|
||||||
if (ret < 0) return ret;
|
|
||||||
|
if (ret == 0)
|
||||||
|
return 0; /* call R2, line 178 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 181 */
|
ret = slice_del(z); /* delete, line 181 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int r_tidy_up(struct SN_env * z) {
|
static int
|
||||||
|
r_tidy_up(struct SN_env * z)
|
||||||
|
{
|
||||||
int among_var;
|
int among_var;
|
||||||
|
|
||||||
z->ket = z->c; /* [, line 186 */
|
z->ket = z->c; /* [, line 186 */
|
||||||
among_var = find_among_b(z, a_7, 4); /* substring, line 186 */
|
among_var = find_among_b(z, a_7, 4); /* substring, line 186 */
|
||||||
if (!(among_var)) return 0;
|
if (!(among_var))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 186 */
|
z->bra = z->c; /* ], line 186 */
|
||||||
switch(among_var) {
|
switch (among_var)
|
||||||
case 0: return 0;
|
{
|
||||||
|
case 0:
|
||||||
|
return 0;
|
||||||
case 1:
|
case 1:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 190 */
|
ret = slice_del(z); /* delete, line 190 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
z->ket = z->c; /* [, line 191 */
|
z->ket = z->c; /* [, line 191 */
|
||||||
if (!(eq_s_b(z, 1, s_6))) return 0;
|
if (!(eq_s_b(z, 1, s_6)))
|
||||||
|
return 0;
|
||||||
z->bra = z->c; /* ], line 191 */
|
z->bra = z->c; /* ], line 191 */
|
||||||
if (!(eq_s_b(z, 1, s_7))) return 0;
|
if (!(eq_s_b(z, 1, s_7)))
|
||||||
{ int ret;
|
return 0;
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 191 */
|
ret = slice_del(z); /* delete, line 191 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (!(eq_s_b(z, 1, s_8))) return 0;
|
if (!(eq_s_b(z, 1, s_8)))
|
||||||
{ int ret;
|
return 0;
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 194 */
|
ret = slice_del(z); /* delete, line 194 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 196 */
|
ret = slice_del(z); /* delete, line 196 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int russian_KOI8_R_stem(struct SN_env * z) {
|
extern int
|
||||||
{ int c = z->c; /* do, line 203 */
|
russian_KOI8_R_stem(struct SN_env * z)
|
||||||
{ int ret = r_mark_regions(z);
|
{
|
||||||
if (ret == 0) goto lab0; /* call mark_regions, line 203 */
|
{
|
||||||
if (ret < 0) return ret;
|
int c = z->c; /* do, line 203 */
|
||||||
|
|
||||||
|
{
|
||||||
|
int ret = r_mark_regions(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab0; /* call mark_regions, line 203 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
lab0:
|
lab0:
|
||||||
z->c = c;
|
z->c = c;
|
||||||
}
|
}
|
||||||
z->lb = z->c; z->c = z->l; /* backwards, line 204 */
|
z->lb = z->c;
|
||||||
|
z->c = z->l; /* backwards, line 204 */
|
||||||
|
|
||||||
{ int m3; /* setlimit, line 204 */
|
{
|
||||||
int m = z->l - z->c; (void) m;
|
int m3; /* setlimit, line 204 */
|
||||||
if (z->c < z->I[0]) return 0;
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m;
|
||||||
|
if (z->c < z->I[0])
|
||||||
|
return 0;
|
||||||
z->c = z->I[0]; /* tomark, line 204 */
|
z->c = z->I[0]; /* tomark, line 204 */
|
||||||
m3 = z->lb; z->lb = z->c;
|
m3 = z->lb;
|
||||||
|
z->lb = z->c;
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int m = z->l - z->c; (void) m; /* do, line 205 */
|
{
|
||||||
{ int m = z->l - z->c; (void) m; /* or, line 206 */
|
int m = z->l - z->c;
|
||||||
{ int ret = r_perfective_gerund(z);
|
|
||||||
if (ret == 0) goto lab3; /* call perfective_gerund, line 206 */
|
(void) m; /* do, line 205 */
|
||||||
if (ret < 0) return ret;
|
{
|
||||||
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m; /* or, line 206 */
|
||||||
|
{
|
||||||
|
int ret = r_perfective_gerund(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab3; /* call perfective_gerund, line 206 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
goto lab2;
|
goto lab2;
|
||||||
lab3:
|
lab3:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int m = z->l - z->c; (void) m; /* try, line 207 */
|
{
|
||||||
{ int ret = r_reflexive(z);
|
int m = z->l - z->c;
|
||||||
if (ret == 0) { z->c = z->l - m; goto lab4; } /* call reflexive, line 207 */
|
|
||||||
if (ret < 0) return ret;
|
(void) m; /* try, line 207 */
|
||||||
|
{
|
||||||
|
int ret = r_reflexive(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab4;
|
||||||
|
} /* call reflexive, line 207 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
lab4:
|
lab4:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; (void) m; /* or, line 208 */
|
{
|
||||||
{ int ret = r_adjectival(z);
|
int m = z->l - z->c;
|
||||||
if (ret == 0) goto lab6; /* call adjectival, line 208 */
|
|
||||||
if (ret < 0) return ret;
|
(void) m; /* or, line 208 */
|
||||||
|
{
|
||||||
|
int ret = r_adjectival(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab6; /* call adjectival, line 208 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
goto lab5;
|
goto lab5;
|
||||||
lab6:
|
lab6:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int ret = r_verb(z);
|
{
|
||||||
if (ret == 0) goto lab7; /* call verb, line 208 */
|
int ret = r_verb(z);
|
||||||
if (ret < 0) return ret;
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab7; /* call verb, line 208 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
goto lab5;
|
goto lab5;
|
||||||
lab7:
|
lab7:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
{ int ret = r_noun(z);
|
{
|
||||||
if (ret == 0) goto lab1; /* call noun, line 208 */
|
int ret = r_noun(z);
|
||||||
if (ret < 0) return ret;
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab1; /* call noun, line 208 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lab5:
|
lab5:
|
||||||
|
@ -662,29 +858,53 @@ extern int russian_KOI8_R_stem(struct SN_env * z) {
|
||||||
lab1:
|
lab1:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; (void) m; /* try, line 211 */
|
{
|
||||||
|
int m = z->l - z->c;
|
||||||
|
|
||||||
|
(void) m; /* try, line 211 */
|
||||||
z->ket = z->c; /* [, line 211 */
|
z->ket = z->c; /* [, line 211 */
|
||||||
if (!(eq_s_b(z, 1, s_9))) { z->c = z->l - m; goto lab8; }
|
if (!(eq_s_b(z, 1, s_9)))
|
||||||
|
{
|
||||||
|
z->c = z->l - m;
|
||||||
|
goto lab8;
|
||||||
|
}
|
||||||
z->bra = z->c; /* ], line 211 */
|
z->bra = z->c; /* ], line 211 */
|
||||||
{ int ret;
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
ret = slice_del(z); /* delete, line 211 */
|
ret = slice_del(z); /* delete, line 211 */
|
||||||
if (ret < 0) return ret;
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
lab8:
|
lab8:
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; (void) m; /* do, line 214 */
|
{
|
||||||
{ int ret = r_derivational(z);
|
int m = z->l - z->c;
|
||||||
if (ret == 0) goto lab9; /* call derivational, line 214 */
|
|
||||||
if (ret < 0) return ret;
|
(void) m; /* do, line 214 */
|
||||||
|
{
|
||||||
|
int ret = r_derivational(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab9; /* call derivational, line 214 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
lab9:
|
lab9:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
}
|
}
|
||||||
{ int m = z->l - z->c; (void) m; /* do, line 215 */
|
{
|
||||||
{ int ret = r_tidy_up(z);
|
int m = z->l - z->c;
|
||||||
if (ret == 0) goto lab10; /* call tidy_up, line 215 */
|
|
||||||
if (ret < 0) return ret;
|
(void) m; /* do, line 215 */
|
||||||
|
{
|
||||||
|
int ret = r_tidy_up(z);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
goto lab10; /* call tidy_up, line 215 */
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
lab10:
|
lab10:
|
||||||
z->c = z->l - m;
|
z->c = z->l - m;
|
||||||
|
@ -695,7 +915,12 @@ extern int russian_KOI8_R_stem(struct SN_env * z) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern struct SN_env * russian_KOI8_R_create_env(void) { return SN_create_env(0, 2, 0); }
|
extern struct SN_env *russian_KOI8_R_create_env(void)
|
||||||
|
{
|
||||||
extern void russian_KOI8_R_close_env(struct SN_env * z) { SN_close_env(z); }
|
return SN_create_env(0, 2, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void russian_KOI8_R_close_env(struct SN_env * z)
|
||||||
|
{
|
||||||
|
SN_close_env(z);
|
||||||
|
}
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
/* This file was generated automatically by the Snowball to ANSI C compiler */
|
/* This file was generated automatically by the Snowball to ANSI C compiler */
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C"
|
||||||
|
{
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern struct SN_env *russian_KOI8_R_create_env(void);
|
extern struct SN_env *russian_KOI8_R_create_env(void);
|
||||||
|
@ -12,5 +13,5 @@ extern int russian_KOI8_R_stem(struct SN_env * z);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -9,18 +9,25 @@
|
||||||
|
|
||||||
#define CREATE_SIZE 1
|
#define CREATE_SIZE 1
|
||||||
|
|
||||||
extern symbol * create_s(void) {
|
extern symbol *
|
||||||
|
create_s(void)
|
||||||
|
{
|
||||||
symbol *p;
|
symbol *p;
|
||||||
void *mem = malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol));
|
void *mem = malloc(HEAD + (CREATE_SIZE + 1) * sizeof(symbol));
|
||||||
if (mem == NULL) return NULL;
|
|
||||||
|
if (mem == NULL)
|
||||||
|
return NULL;
|
||||||
p = (symbol *) (HEAD + (char *) mem);
|
p = (symbol *) (HEAD + (char *) mem);
|
||||||
CAPACITY(p) = CREATE_SIZE;
|
CAPACITY(p) = CREATE_SIZE;
|
||||||
SET_SIZE(p, CREATE_SIZE);
|
SET_SIZE(p, CREATE_SIZE);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void lose_s(symbol * p) {
|
extern void
|
||||||
if (p == NULL) return;
|
lose_s(symbol * p)
|
||||||
|
{
|
||||||
|
if (p == NULL)
|
||||||
|
return;
|
||||||
free((char *) p - HEAD);
|
free((char *) p - HEAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,29 +39,45 @@ extern void lose_s(symbol * p) {
|
||||||
-- used to implement hop and next in the utf8 case.
|
-- used to implement hop and next in the utf8 case.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern int skip_utf8(const symbol * p, int c, int lb, int l, int n) {
|
extern int
|
||||||
|
skip_utf8(const symbol * p, int c, int lb, int l, int n)
|
||||||
|
{
|
||||||
int b;
|
int b;
|
||||||
if (n >= 0) {
|
|
||||||
for (; n > 0; n--) {
|
if (n >= 0)
|
||||||
if (c >= l) return -1;
|
{
|
||||||
|
for (; n > 0; n--)
|
||||||
|
{
|
||||||
|
if (c >= l)
|
||||||
|
return -1;
|
||||||
b = p[c++];
|
b = p[c++];
|
||||||
if (b >= 0xC0) { /* 1100 0000 */
|
if (b >= 0xC0)
|
||||||
while (c < l) {
|
{ /* 1100 0000 */
|
||||||
|
while (c < l)
|
||||||
|
{
|
||||||
b = p[c];
|
b = p[c];
|
||||||
if (b >= 0xC0 || b < 0x80) break;
|
if (b >= 0xC0 || b < 0x80)
|
||||||
|
break;
|
||||||
/* break unless b is 10------ */
|
/* break unless b is 10------ */
|
||||||
c++;
|
c++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
for (; n < 0; n++) {
|
else
|
||||||
if (c <= lb) return -1;
|
{
|
||||||
|
for (; n < 0; n++)
|
||||||
|
{
|
||||||
|
if (c <= lb)
|
||||||
|
return -1;
|
||||||
b = p[--c];
|
b = p[--c];
|
||||||
if (b >= 0x80) { /* 1000 0000 */
|
if (b >= 0x80)
|
||||||
while (c > lb) {
|
{ /* 1000 0000 */
|
||||||
|
while (c > lb)
|
||||||
|
{
|
||||||
b = p[c];
|
b = p[c];
|
||||||
if (b >= 0xC0) break; /* 1100 0000 */
|
if (b >= 0xC0)
|
||||||
|
break; /* 1100 0000 */
|
||||||
c--;
|
c--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,124 +88,199 @@ extern int skip_utf8(const symbol * p, int c, int lb, int l, int n) {
|
||||||
|
|
||||||
/* Code for character groupings: utf8 cases */
|
/* Code for character groupings: utf8 cases */
|
||||||
|
|
||||||
static int get_utf8(const symbol * p, int c, int l, int * slot) {
|
static int
|
||||||
int b0, b1;
|
get_utf8(const symbol * p, int c, int l, int *slot)
|
||||||
if (c >= l) return 0;
|
{
|
||||||
|
int b0,
|
||||||
|
b1;
|
||||||
|
|
||||||
|
if (c >= l)
|
||||||
|
return 0;
|
||||||
b0 = p[c++];
|
b0 = p[c++];
|
||||||
if (b0 < 0xC0 || c == l) { /* 1100 0000 */
|
if (b0 < 0xC0 || c == l)
|
||||||
* slot = b0; return 1;
|
{ /* 1100 0000 */
|
||||||
|
*slot = b0;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
b1 = p[c++];
|
b1 = p[c++];
|
||||||
if (b0 < 0xE0 || c == l) { /* 1110 0000 */
|
if (b0 < 0xE0 || c == l)
|
||||||
* slot = (b0 & 0x1F) << 6 | (b1 & 0x3F); return 2;
|
{ /* 1110 0000 */
|
||||||
|
*slot = (b0 & 0x1F) << 6 | (b1 & 0x3F);
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
* slot = (b0 & 0xF) << 12 | (b1 & 0x3F) << 6 | (*p & 0x3F); return 3;
|
*slot = (b0 & 0xF) << 12 | (b1 & 0x3F) << 6 | (*p & 0x3F);
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int get_b_utf8(const symbol * p, int c, int lb, int * slot) {
|
static int
|
||||||
int b0, b1;
|
get_b_utf8(const symbol * p, int c, int lb, int *slot)
|
||||||
if (c <= lb) return 0;
|
{
|
||||||
|
int b0,
|
||||||
|
b1;
|
||||||
|
|
||||||
|
if (c <= lb)
|
||||||
|
return 0;
|
||||||
b0 = p[--c];
|
b0 = p[--c];
|
||||||
if (b0 < 0x80 || c == lb) { /* 1000 0000 */
|
if (b0 < 0x80 || c == lb)
|
||||||
* slot = b0; return 1;
|
{ /* 1000 0000 */
|
||||||
|
*slot = b0;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
b1 = p[--c];
|
b1 = p[--c];
|
||||||
if (b1 >= 0xC0 || c == lb) { /* 1100 0000 */
|
if (b1 >= 0xC0 || c == lb)
|
||||||
* slot = (b1 & 0x1F) << 6 | (b0 & 0x3F); return 2;
|
{ /* 1100 0000 */
|
||||||
|
*slot = (b1 & 0x1F) << 6 | (b0 & 0x3F);
|
||||||
|
return 2;
|
||||||
}
|
}
|
||||||
* slot = (*p & 0xF) << 12 | (b1 & 0x3F) << 6 | (b0 & 0x3F); return 3;
|
*slot = (*p & 0xF) << 12 | (b1 & 0x3F) << 6 | (b0 & 0x3F);
|
||||||
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int in_grouping_U(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
in_grouping_U(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
int w = get_utf8(z->p, z->c, z->l, &ch);
|
int w = get_utf8(z->p, z->c, z->l, &ch);
|
||||||
|
|
||||||
unless(w) return 0;
|
unless(w) return 0;
|
||||||
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||||
z->c += w; return 1;
|
return 0;
|
||||||
|
z->c += w;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int in_grouping_b_U(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
in_grouping_b_U(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
int w = get_b_utf8(z->p, z->c, z->lb, &ch);
|
int w = get_b_utf8(z->p, z->c, z->lb, &ch);
|
||||||
|
|
||||||
unless(w) return 0;
|
unless(w) return 0;
|
||||||
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||||
z->c -= w; return 1;
|
return 0;
|
||||||
|
z->c -= w;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_grouping_U(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
out_grouping_U(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
int w = get_utf8(z->p, z->c, z->l, &ch);
|
int w = get_utf8(z->p, z->c, z->l, &ch);
|
||||||
|
|
||||||
unless(w) return 0;
|
unless(w) return 0;
|
||||||
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
||||||
z->c += w; return 1;
|
z->c += w;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_grouping_b_U(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
out_grouping_b_U(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
int w = get_b_utf8(z->p, z->c, z->lb, &ch);
|
int w = get_b_utf8(z->p, z->c, z->lb, &ch);
|
||||||
|
|
||||||
unless(w) return 0;
|
unless(w) return 0;
|
||||||
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
||||||
z->c -= w; return 1;
|
z->c -= w;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Code for character groupings: non-utf8 cases */
|
/* Code for character groupings: non-utf8 cases */
|
||||||
|
|
||||||
extern int in_grouping(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
in_grouping(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
if (z->c >= z->l) return 0;
|
|
||||||
|
if (z->c >= z->l)
|
||||||
|
return 0;
|
||||||
ch = z->p[z->c];
|
ch = z->p[z->c];
|
||||||
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||||
z->c++; return 1;
|
return 0;
|
||||||
|
z->c++;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int in_grouping_b(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
in_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
if (z->c <= z->lb) return 0;
|
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
ch = z->p[z->c - 1];
|
ch = z->p[z->c - 1];
|
||||||
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
if (ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0)
|
||||||
z->c--; return 1;
|
return 0;
|
||||||
|
z->c--;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_grouping(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
out_grouping(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
if (z->c >= z->l) return 0;
|
|
||||||
|
if (z->c >= z->l)
|
||||||
|
return 0;
|
||||||
ch = z->p[z->c];
|
ch = z->p[z->c];
|
||||||
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
||||||
z->c++; return 1;
|
z->c++;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int out_grouping_b(struct SN_env * z, unsigned char * s, int min, int max) {
|
extern int
|
||||||
|
out_grouping_b(struct SN_env * z, unsigned char *s, int min, int max)
|
||||||
|
{
|
||||||
int ch;
|
int ch;
|
||||||
if (z->c <= z->lb) return 0;
|
|
||||||
|
if (z->c <= z->lb)
|
||||||
|
return 0;
|
||||||
ch = z->p[z->c - 1];
|
ch = z->p[z->c - 1];
|
||||||
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
unless(ch > max || (ch -= min) < 0 || (s[ch >> 3] & (0X1 << (ch & 0X7))) == 0) return 0;
|
||||||
z->c--; return 1;
|
z->c--;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_s(struct SN_env * z, int s_size, symbol * s) {
|
extern int
|
||||||
if (z->l - z->c < s_size || memcmp(z->p + z->c, s, s_size * sizeof(symbol)) != 0) return 0;
|
eq_s(struct SN_env * z, int s_size, symbol * s)
|
||||||
z->c += s_size; return 1;
|
{
|
||||||
|
if (z->l - z->c < s_size || memcmp(z->p + z->c, s, s_size * sizeof(symbol)) != 0)
|
||||||
|
return 0;
|
||||||
|
z->c += s_size;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_s_b(struct SN_env * z, int s_size, symbol * s) {
|
extern int
|
||||||
if (z->c - z->lb < s_size || memcmp(z->p + z->c - s_size, s, s_size * sizeof(symbol)) != 0) return 0;
|
eq_s_b(struct SN_env * z, int s_size, symbol * s)
|
||||||
z->c -= s_size; return 1;
|
{
|
||||||
|
if (z->c - z->lb < s_size || memcmp(z->p + z->c - s_size, s, s_size * sizeof(symbol)) != 0)
|
||||||
|
return 0;
|
||||||
|
z->c -= s_size;
|
||||||
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_v(struct SN_env * z, symbol * p) {
|
extern int
|
||||||
|
eq_v(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
return eq_s(z, SIZE(p), p);
|
return eq_s(z, SIZE(p), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int eq_v_b(struct SN_env * z, symbol * p) {
|
extern int
|
||||||
|
eq_v_b(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
return eq_s_b(z, SIZE(p), p);
|
return eq_s_b(z, SIZE(p), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int find_among(struct SN_env * z, struct among * v, int v_size) {
|
extern int
|
||||||
|
find_among(struct SN_env * z, struct among * v, int v_size)
|
||||||
|
{
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = v_size;
|
int j = v_size;
|
||||||
|
|
||||||
int c = z->c; int l = z->l;
|
int c = z->c;
|
||||||
|
int l = z->l;
|
||||||
symbol *q = z->p + c;
|
symbol *q = z->p + c;
|
||||||
|
|
||||||
struct among *w;
|
struct among *w;
|
||||||
|
@ -192,57 +290,89 @@ extern int find_among(struct SN_env * z, struct among * v, int v_size) {
|
||||||
|
|
||||||
int first_key_inspected = 0;
|
int first_key_inspected = 0;
|
||||||
|
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
int k = i + ((j - i) >> 1);
|
int k = i + ((j - i) >> 1);
|
||||||
int diff = 0;
|
int diff = 0;
|
||||||
int common = common_i < common_j ? common_i : common_j; /* smaller */
|
int common = common_i < common_j ? common_i : common_j; /* smaller */
|
||||||
|
|
||||||
w = v + k;
|
w = v + k;
|
||||||
{
|
{
|
||||||
int i; for (i = common; i < w->s_size; i++) {
|
int i;
|
||||||
if (c + common == l) { diff = -1; break; }
|
|
||||||
|
for (i = common; i < w->s_size; i++)
|
||||||
|
{
|
||||||
|
if (c + common == l)
|
||||||
|
{
|
||||||
|
diff = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
diff = q[common] - w->s[i];
|
diff = q[common] - w->s[i];
|
||||||
if (diff != 0) break;
|
if (diff != 0)
|
||||||
|
break;
|
||||||
common++;
|
common++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diff < 0) { j = k; common_j = common; }
|
if (diff < 0)
|
||||||
else { i = k; common_i = common; }
|
{
|
||||||
if (j - i <= 1) {
|
j = k;
|
||||||
if (i > 0) break; /* v->s has been inspected */
|
common_j = common;
|
||||||
if (j == i) break; /* only one item in v */
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
i = k;
|
||||||
|
common_i = common;
|
||||||
|
}
|
||||||
|
if (j - i <= 1)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
break; /* v->s has been inspected */
|
||||||
|
if (j == i)
|
||||||
|
break; /* only one item in v */
|
||||||
|
|
||||||
/* - but now we need to go round once more to get
|
/*
|
||||||
v->s inspected. This looks messy, but is actually
|
* - but now we need to go round once more to get v->s inspected.
|
||||||
the optimal approach. */
|
* This looks messy, but is actually the optimal approach.
|
||||||
|
*/
|
||||||
|
|
||||||
if (first_key_inspected) break;
|
if (first_key_inspected)
|
||||||
|
break;
|
||||||
first_key_inspected = 1;
|
first_key_inspected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
w = v + i;
|
w = v + i;
|
||||||
if (common_i >= w->s_size) {
|
if (common_i >= w->s_size)
|
||||||
|
{
|
||||||
z->c = c + w->s_size;
|
z->c = c + w->s_size;
|
||||||
if (w->function == 0) return w->result;
|
if (w->function == 0)
|
||||||
|
return w->result;
|
||||||
{
|
{
|
||||||
int res = w->function(z);
|
int res = w->function(z);
|
||||||
|
|
||||||
z->c = c + w->s_size;
|
z->c = c + w->s_size;
|
||||||
if (res) return w->result;
|
if (res)
|
||||||
|
return w->result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = w->substring_i;
|
i = w->substring_i;
|
||||||
if (i < 0) return 0;
|
if (i < 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* find_among_b is for backwards processing. Same comments apply */
|
/* find_among_b is for backwards processing. Same comments apply */
|
||||||
|
|
||||||
extern int find_among_b(struct SN_env * z, struct among * v, int v_size) {
|
extern int
|
||||||
|
find_among_b(struct SN_env * z, struct among * v, int v_size)
|
||||||
|
{
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int j = v_size;
|
int j = v_size;
|
||||||
|
|
||||||
int c = z->c; int lb = z->lb;
|
int c = z->c;
|
||||||
|
int lb = z->lb;
|
||||||
symbol *q = z->p + c - 1;
|
symbol *q = z->p + c - 1;
|
||||||
|
|
||||||
struct among *w;
|
struct among *w;
|
||||||
|
@ -252,41 +382,69 @@ extern int find_among_b(struct SN_env * z, struct among * v, int v_size) {
|
||||||
|
|
||||||
int first_key_inspected = 0;
|
int first_key_inspected = 0;
|
||||||
|
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
int k = i + ((j - i) >> 1);
|
int k = i + ((j - i) >> 1);
|
||||||
int diff = 0;
|
int diff = 0;
|
||||||
int common = common_i < common_j ? common_i : common_j;
|
int common = common_i < common_j ? common_i : common_j;
|
||||||
|
|
||||||
w = v + k;
|
w = v + k;
|
||||||
{
|
{
|
||||||
int i; for (i = w->s_size - 1 - common; i >= 0; i--) {
|
int i;
|
||||||
if (c - common == lb) { diff = -1; break; }
|
|
||||||
|
for (i = w->s_size - 1 - common; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (c - common == lb)
|
||||||
|
{
|
||||||
|
diff = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
diff = q[-common] - w->s[i];
|
diff = q[-common] - w->s[i];
|
||||||
if (diff != 0) break;
|
if (diff != 0)
|
||||||
|
break;
|
||||||
common++;
|
common++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (diff < 0) { j = k; common_j = common; }
|
if (diff < 0)
|
||||||
else { i = k; common_i = common; }
|
{
|
||||||
if (j - i <= 1) {
|
j = k;
|
||||||
if (i > 0) break;
|
common_j = common;
|
||||||
if (j == i) break;
|
}
|
||||||
if (first_key_inspected) break;
|
else
|
||||||
|
{
|
||||||
|
i = k;
|
||||||
|
common_i = common;
|
||||||
|
}
|
||||||
|
if (j - i <= 1)
|
||||||
|
{
|
||||||
|
if (i > 0)
|
||||||
|
break;
|
||||||
|
if (j == i)
|
||||||
|
break;
|
||||||
|
if (first_key_inspected)
|
||||||
|
break;
|
||||||
first_key_inspected = 1;
|
first_key_inspected = 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
while(1) {
|
while (1)
|
||||||
|
{
|
||||||
w = v + i;
|
w = v + i;
|
||||||
if (common_i >= w->s_size) {
|
if (common_i >= w->s_size)
|
||||||
|
{
|
||||||
z->c = c - w->s_size;
|
z->c = c - w->s_size;
|
||||||
if (w->function == 0) return w->result;
|
if (w->function == 0)
|
||||||
|
return w->result;
|
||||||
{
|
{
|
||||||
int res = w->function(z);
|
int res = w->function(z);
|
||||||
|
|
||||||
z->c = c - w->s_size;
|
z->c = c - w->s_size;
|
||||||
if (res) return w->result;
|
if (res)
|
||||||
|
return w->result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
i = w->substring_i;
|
i = w->substring_i;
|
||||||
if (i < 0) return 0;
|
if (i < 0)
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -294,12 +452,16 @@ extern int find_among_b(struct SN_env * z, struct among * v, int v_size) {
|
||||||
/* Increase the size of the buffer pointed to by p to at least n symbols.
|
/* Increase the size of the buffer pointed to by p to at least n symbols.
|
||||||
* If insufficient memory, returns NULL and frees the old buffer.
|
* If insufficient memory, returns NULL and frees the old buffer.
|
||||||
*/
|
*/
|
||||||
static symbol * increase_size(symbol * p, int n) {
|
static symbol *
|
||||||
|
increase_size(symbol * p, int n)
|
||||||
|
{
|
||||||
symbol *q;
|
symbol *q;
|
||||||
int new_size = n + 20;
|
int new_size = n + 20;
|
||||||
void *mem = realloc((char *) p - HEAD,
|
void *mem = realloc((char *) p - HEAD,
|
||||||
HEAD + (new_size + 1) * sizeof(symbol));
|
HEAD + (new_size + 1) * sizeof(symbol));
|
||||||
if (mem == NULL) {
|
|
||||||
|
if (mem == NULL)
|
||||||
|
{
|
||||||
lose_s(p);
|
lose_s(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -313,20 +475,27 @@ static symbol * increase_size(symbol * p, int n) {
|
||||||
Returns 0 on success, -1 on error.
|
Returns 0 on success, -1 on error.
|
||||||
Also, frees z->p (and sets it to NULL) on error.
|
Also, frees z->p (and sets it to NULL) on error.
|
||||||
*/
|
*/
|
||||||
extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s, int * adjptr)
|
extern int
|
||||||
|
replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const symbol * s, int *adjptr)
|
||||||
{
|
{
|
||||||
int adjustment;
|
int adjustment;
|
||||||
int len;
|
int len;
|
||||||
if (z->p == NULL) {
|
|
||||||
|
if (z->p == NULL)
|
||||||
|
{
|
||||||
z->p = create_s();
|
z->p = create_s();
|
||||||
if (z->p == NULL) return -1;
|
if (z->p == NULL)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
adjustment = s_size - (c_ket - c_bra);
|
adjustment = s_size - (c_ket - c_bra);
|
||||||
len = SIZE(z->p);
|
len = SIZE(z->p);
|
||||||
if (adjustment != 0) {
|
if (adjustment != 0)
|
||||||
if (adjustment + len > CAPACITY(z->p)) {
|
{
|
||||||
|
if (adjustment + len > CAPACITY(z->p))
|
||||||
|
{
|
||||||
z->p = increase_size(z->p, adjustment + len);
|
z->p = increase_size(z->p, adjustment + len);
|
||||||
if (z->p == NULL) return -1;
|
if (z->p == NULL)
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
memmove(z->p + c_ket + adjustment,
|
memmove(z->p + c_ket + adjustment,
|
||||||
z->p + c_ket,
|
z->p + c_ket,
|
||||||
|
@ -335,8 +504,7 @@ extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const
|
||||||
z->l += adjustment;
|
z->l += adjustment;
|
||||||
if (z->c >= c_ket)
|
if (z->c >= c_ket)
|
||||||
z->c += adjustment;
|
z->c += adjustment;
|
||||||
else
|
else if (z->c > c_bra)
|
||||||
if (z->c > c_bra)
|
|
||||||
z->c = c_bra;
|
z->c = c_bra;
|
||||||
}
|
}
|
||||||
unless(s_size == 0) memmove(z->p + c_bra, s, s_size * sizeof(symbol));
|
unless(s_size == 0) memmove(z->p + c_bra, s, s_size * sizeof(symbol));
|
||||||
|
@ -345,7 +513,9 @@ extern int replace_s(struct SN_env * z, int c_bra, int c_ket, int s_size, const
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int slice_check(struct SN_env * z) {
|
static int
|
||||||
|
slice_check(struct SN_env * z)
|
||||||
|
{
|
||||||
|
|
||||||
if (z->bra < 0 ||
|
if (z->bra < 0 ||
|
||||||
z->bra > z->ket ||
|
z->bra > z->ket ||
|
||||||
|
@ -362,45 +532,67 @@ static int slice_check(struct SN_env * z) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int slice_from_s(struct SN_env * z, int s_size, symbol * s) {
|
extern int
|
||||||
if (slice_check(z)) return -1;
|
slice_from_s(struct SN_env * z, int s_size, symbol * s)
|
||||||
|
{
|
||||||
|
if (slice_check(z))
|
||||||
|
return -1;
|
||||||
return replace_s(z, z->bra, z->ket, s_size, s, NULL);
|
return replace_s(z, z->bra, z->ket, s_size, s, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int slice_from_v(struct SN_env * z, symbol * p) {
|
extern int
|
||||||
|
slice_from_v(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
return slice_from_s(z, SIZE(p), p);
|
return slice_from_s(z, SIZE(p), p);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int slice_del(struct SN_env * z) {
|
extern int
|
||||||
|
slice_del(struct SN_env * z)
|
||||||
|
{
|
||||||
return slice_from_s(z, 0, 0);
|
return slice_from_s(z, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s) {
|
extern int
|
||||||
|
insert_s(struct SN_env * z, int bra, int ket, int s_size, symbol * s)
|
||||||
|
{
|
||||||
int adjustment;
|
int adjustment;
|
||||||
|
|
||||||
if (replace_s(z, bra, ket, s_size, s, &adjustment))
|
if (replace_s(z, bra, ket, s_size, s, &adjustment))
|
||||||
return -1;
|
return -1;
|
||||||
if (bra <= z->bra) z->bra += adjustment;
|
if (bra <= z->bra)
|
||||||
if (bra <= z->ket) z->ket += adjustment;
|
z->bra += adjustment;
|
||||||
|
if (bra <= z->ket)
|
||||||
|
z->ket += adjustment;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern int insert_v(struct SN_env * z, int bra, int ket, symbol * p) {
|
extern int
|
||||||
|
insert_v(struct SN_env * z, int bra, int ket, symbol * p)
|
||||||
|
{
|
||||||
int adjustment;
|
int adjustment;
|
||||||
|
|
||||||
if (replace_s(z, bra, ket, SIZE(p), p, &adjustment))
|
if (replace_s(z, bra, ket, SIZE(p), p, &adjustment))
|
||||||
return -1;
|
return -1;
|
||||||
if (bra <= z->bra) z->bra += adjustment;
|
if (bra <= z->bra)
|
||||||
if (bra <= z->ket) z->ket += adjustment;
|
z->bra += adjustment;
|
||||||
|
if (bra <= z->ket)
|
||||||
|
z->ket += adjustment;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern symbol * slice_to(struct SN_env * z, symbol * p) {
|
extern symbol *
|
||||||
if (slice_check(z)) {
|
slice_to(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
|
if (slice_check(z))
|
||||||
|
{
|
||||||
lose_s(p);
|
lose_s(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
int len = z->ket - z->bra;
|
int len = z->ket - z->bra;
|
||||||
if (CAPACITY(p) < len) {
|
|
||||||
|
if (CAPACITY(p) < len)
|
||||||
|
{
|
||||||
p = increase_size(p, len);
|
p = increase_size(p, len);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -411,9 +603,13 @@ extern symbol * slice_to(struct SN_env * z, symbol * p) {
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern symbol * assign_to(struct SN_env * z, symbol * p) {
|
extern symbol *
|
||||||
|
assign_to(struct SN_env * z, symbol * p)
|
||||||
|
{
|
||||||
int len = z->l;
|
int len = z->l;
|
||||||
if (CAPACITY(p) < len) {
|
|
||||||
|
if (CAPACITY(p) < len)
|
||||||
|
{
|
||||||
p = increase_size(p, len);
|
p = increase_size(p, len);
|
||||||
if (p == NULL)
|
if (p == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
@ -424,23 +620,37 @@ extern symbol * assign_to(struct SN_env * z, symbol * p) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
extern void debug(struct SN_env * z, int number, int line_count) {
|
extern void
|
||||||
|
debug(struct SN_env * z, int number, int line_count)
|
||||||
|
{
|
||||||
int i;
|
int i;
|
||||||
int limit = SIZE(z->p);
|
int limit = SIZE(z->p);
|
||||||
|
|
||||||
/* if (number >= 0) printf("%3d (line %4d): '", number, line_count); */
|
/* if (number >= 0) printf("%3d (line %4d): '", number, line_count); */
|
||||||
if (number >= 0) printf("%3d (line %4d): [%d]'", number, line_count,limit);
|
if (number >= 0)
|
||||||
for (i = 0; i <= limit; i++) {
|
printf("%3d (line %4d): [%d]'", number, line_count, limit);
|
||||||
if (z->lb == i) printf("{");
|
for (i = 0; i <= limit; i++)
|
||||||
if (z->bra == i) printf("[");
|
{
|
||||||
if (z->c == i) printf("|");
|
if (z->lb == i)
|
||||||
if (z->ket == i) printf("]");
|
printf("{");
|
||||||
if (z->l == i) printf("}");
|
if (z->bra == i)
|
||||||
|
printf("[");
|
||||||
|
if (z->c == i)
|
||||||
|
printf("|");
|
||||||
|
if (z->ket == i)
|
||||||
|
printf("]");
|
||||||
|
if (z->l == i)
|
||||||
|
printf("}");
|
||||||
if (i < limit)
|
if (i < limit)
|
||||||
{ int ch = z->p[i];
|
{
|
||||||
if (ch == 0) ch = '#';
|
int ch = z->p[i];
|
||||||
|
|
||||||
|
if (ch == 0)
|
||||||
|
ch = '#';
|
||||||
printf("%c", ch);
|
printf("%c", ch);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
printf("'\n");
|
printf("'\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -355,8 +355,7 @@ parsetext_v2(TSCfgInfo * cfg, PRSTEXT * prs, char *buf, int4 buflen)
|
||||||
prs->curwords++;
|
prs->curwords++;
|
||||||
}
|
}
|
||||||
pfree(norms);
|
pfree(norms);
|
||||||
break; /* lexem already normalized or is stop
|
break; /* lexem already normalized or is stop word */
|
||||||
* word */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,8 +480,7 @@ hlparsetext(TSCfgInfo * cfg, HLPRSTEXT * prs, QUERYTYPE * query, char *buf, int4
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
pfree(norms);
|
pfree(norms);
|
||||||
break; /* lexem already normalized or is stop
|
break; /* lexem already normalized or is stop word */
|
||||||
* word */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/contrib/vacuumlo/vacuumlo.c,v 1.29 2004/12/31 21:58:50 pgsql Exp $
|
* $PostgreSQL: pgsql/contrib/vacuumlo/vacuumlo.c,v 1.30 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -130,8 +130,8 @@ vacuumlo(char *database, struct _param * param)
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Vacuum the temp table so that planner will generate decent plans
|
* Vacuum the temp table so that planner will generate decent plans for
|
||||||
* for the DELETEs below.
|
* the DELETEs below.
|
||||||
*/
|
*/
|
||||||
buf[0] = '\0';
|
buf[0] = '\0';
|
||||||
strcat(buf, "VACUUM ANALYZE vacuum_l");
|
strcat(buf, "VACUUM ANALYZE vacuum_l");
|
||||||
|
@ -193,8 +193,8 @@ vacuumlo(char *database, struct _param * param)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The "IN" construct used here was horribly inefficient before
|
* The "IN" construct used here was horribly inefficient before
|
||||||
* Postgres 7.4, but should be now competitive if not better than
|
* Postgres 7.4, but should be now competitive if not better than the
|
||||||
* the bogus join we used before.
|
* bogus join we used before.
|
||||||
*/
|
*/
|
||||||
snprintf(buf, BUFSIZE,
|
snprintf(buf, BUFSIZE,
|
||||||
"DELETE FROM vacuum_l "
|
"DELETE FROM vacuum_l "
|
||||||
|
@ -216,10 +216,9 @@ vacuumlo(char *database, struct _param * param)
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Run the actual deletes in a single transaction. Note that this
|
* Run the actual deletes in a single transaction. Note that this would
|
||||||
* would be a bad idea in pre-7.1 Postgres releases (since rolling
|
* be a bad idea in pre-7.1 Postgres releases (since rolling back a table
|
||||||
* back a table delete used to cause problems), but it should be safe
|
* delete used to cause problems), but it should be safe now.
|
||||||
* now.
|
|
||||||
*/
|
*/
|
||||||
res = PQexec(conn, "begin");
|
res = PQexec(conn, "begin");
|
||||||
PQclear(res);
|
PQclear(res);
|
||||||
|
|
|
@ -197,7 +197,8 @@ xml_encode_special_chars(PG_FUNCTION_ARGS)
|
||||||
text *tin = PG_GETARG_TEXT_P(0);
|
text *tin = PG_GETARG_TEXT_P(0);
|
||||||
text *tout;
|
text *tout;
|
||||||
int32 ressize;
|
int32 ressize;
|
||||||
xmlChar *ts, *tt;
|
xmlChar *ts,
|
||||||
|
*tt;
|
||||||
|
|
||||||
ts = pgxml_texttoxmlchar(tin);
|
ts = pgxml_texttoxmlchar(tin);
|
||||||
|
|
||||||
|
@ -225,15 +226,15 @@ pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
|
||||||
/* Function translates a nodeset into a text representation */
|
/* Function translates a nodeset into a text representation */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* iterates over each node in the set and calls xmlNodeDump to write
|
* iterates over each node in the set and calls xmlNodeDump to write it to
|
||||||
* it to an xmlBuffer -from which an xmlChar * string is returned.
|
* an xmlBuffer -from which an xmlChar * string is returned.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* each representation is surrounded by <tagname> ... </tagname> */
|
/* each representation is surrounded by <tagname> ... </tagname> */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* plainsep is an ordinary (not tag) seperator - if used, then nodes
|
* plainsep is an ordinary (not tag) seperator - if used, then nodes are
|
||||||
* are cast to string as output method
|
* cast to string as output method
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -412,8 +413,8 @@ xpath_string(PG_FUNCTION_ARGS)
|
||||||
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
|
pathsize = VARSIZE(xpathsupp) - VARHDRSZ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We encapsulate the supplied path with "string()" = 8 chars + 1 for
|
* We encapsulate the supplied path with "string()" = 8 chars + 1 for NUL
|
||||||
* NUL at end
|
* at end
|
||||||
*/
|
*/
|
||||||
/* We could try casting to string using the libxml function? */
|
/* We could try casting to string using the libxml function? */
|
||||||
|
|
||||||
|
@ -663,8 +664,8 @@ xpath_table(PG_FUNCTION_ARGS)
|
||||||
int proc;
|
int proc;
|
||||||
int i;
|
int i;
|
||||||
int j;
|
int j;
|
||||||
int rownr; /* For issuing multiple rows from one
|
int rownr; /* For issuing multiple rows from one original
|
||||||
* original document */
|
* document */
|
||||||
int had_values; /* To determine end of nodeset results */
|
int had_values; /* To determine end of nodeset results */
|
||||||
|
|
||||||
StringInfo querysql;
|
StringInfo querysql;
|
||||||
|
@ -689,14 +690,16 @@ xpath_table(PG_FUNCTION_ARGS)
|
||||||
errmsg("xpath_table requires Materialize mode, but it is not "
|
errmsg("xpath_table requires Materialize mode, but it is not "
|
||||||
"allowed in this context")));
|
"allowed in this context")));
|
||||||
|
|
||||||
/* The tuplestore must exist in a higher context than
|
/*
|
||||||
* this function call (per_query_ctx is used)
|
* The tuplestore must exist in a higher context than this function call
|
||||||
|
* (per_query_ctx is used)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
|
||||||
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||||
|
|
||||||
/* Create the tuplestore - work_mem is the max in-memory size before a
|
/*
|
||||||
|
* Create the tuplestore - work_mem is the max in-memory size before a
|
||||||
* file is created on disk to hold it.
|
* file is created on disk to hold it.
|
||||||
*/
|
*/
|
||||||
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
tupstore = tuplestore_begin_heap(true, false, work_mem);
|
||||||
|
@ -707,11 +710,11 @@ xpath_table(PG_FUNCTION_ARGS)
|
||||||
ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
|
ret_tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At the moment we assume that the returned attributes make sense for
|
* At the moment we assume that the returned attributes make sense for the
|
||||||
* the XPath specififed (i.e. we trust the caller). It's not fatal if
|
* XPath specififed (i.e. we trust the caller). It's not fatal if they get
|
||||||
* they get it wrong - the input function for the column type will
|
* it wrong - the input function for the column type will raise an error
|
||||||
* raise an error if the path result can't be converted into the
|
* if the path result can't be converted into the correct binary
|
||||||
* correct binary representation.
|
* representation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
|
attinmeta = TupleDescGetAttInMetadata(ret_tupdesc);
|
||||||
|
@ -810,8 +813,8 @@ xpath_table(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the values array, so that not-well-formed documents
|
* Clear the values array, so that not-well-formed documents return
|
||||||
* return NULL in all columns.
|
* NULL in all columns.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Note that this also means that spare columns will be NULL. */
|
/* Note that this also means that spare columns will be NULL. */
|
||||||
|
@ -825,8 +828,7 @@ xpath_table(PG_FUNCTION_ARGS)
|
||||||
doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
|
doctree = xmlParseMemory(xmldoc, strlen(xmldoc));
|
||||||
|
|
||||||
if (doctree == NULL)
|
if (doctree == NULL)
|
||||||
{ /* not well-formed, so output all-NULL
|
{ /* not well-formed, so output all-NULL tuple */
|
||||||
* tuple */
|
|
||||||
|
|
||||||
ret_tuple = BuildTupleFromCStrings(attinmeta, values);
|
ret_tuple = BuildTupleFromCStrings(attinmeta, values);
|
||||||
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
oldcontext = MemoryContextSwitchTo(per_query_ctx);
|
||||||
|
@ -933,10 +935,10 @@ xpath_table(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
* SFRM_Materialize mode expects us to return a NULL Datum. The actual
|
||||||
* tuples are in our tuplestore and passed back through
|
* tuples are in our tuplestore and passed back through rsinfo->setResult.
|
||||||
* rsinfo->setResult. rsinfo->setDesc is set to the tuple description
|
* rsinfo->setDesc is set to the tuple description that we actually used
|
||||||
* that we actually used to build our tuples with, so the caller can
|
* to build our tuples with, so the caller can verify we did what it was
|
||||||
* verify we did what it was expecting.
|
* expecting.
|
||||||
*/
|
*/
|
||||||
return (Datum) 0;
|
return (Datum) 0;
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.99 2005/03/21 01:23:55 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.100 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -452,8 +452,8 @@ nocachegetattr(HeapTuple tuple,
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In for(), we test <= and not < because we want to see if we
|
* In for(), we test <= and not < because we want to see if we can
|
||||||
* can go past it in initializing offsets.
|
* go past it in initializing offsets.
|
||||||
*/
|
*/
|
||||||
for (j = 0; j <= attnum; j++)
|
for (j = 0; j <= attnum; j++)
|
||||||
{
|
{
|
||||||
|
@ -467,10 +467,9 @@ nocachegetattr(HeapTuple tuple,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If slow is false, and we got here, we know that we have a tuple
|
* If slow is false, and we got here, we know that we have a tuple with no
|
||||||
* with no nulls or var-widths before the target attribute. If
|
* nulls or var-widths before the target attribute. If possible, we also
|
||||||
* possible, we also want to initialize the remainder of the attribute
|
* want to initialize the remainder of the attribute cached offset values.
|
||||||
* cached offset values.
|
|
||||||
*/
|
*/
|
||||||
if (!slow)
|
if (!slow)
|
||||||
{
|
{
|
||||||
|
@ -513,11 +512,11 @@ nocachegetattr(HeapTuple tuple,
|
||||||
/*
|
/*
|
||||||
* Now we know that we have to walk the tuple CAREFULLY.
|
* Now we know that we have to walk the tuple CAREFULLY.
|
||||||
*
|
*
|
||||||
* Note - This loop is a little tricky. For each non-null attribute,
|
* Note - This loop is a little tricky. For each non-null attribute, we
|
||||||
* we have to first account for alignment padding before the attr,
|
* have to first account for alignment padding before the attr, then
|
||||||
* then advance over the attr based on its length. Nulls have no
|
* advance over the attr based on its length. Nulls have no storage
|
||||||
* storage and no alignment padding either. We can use/set attcacheoff
|
* and no alignment padding either. We can use/set attcacheoff until
|
||||||
* until we pass either a null or a var-width attribute.
|
* we pass either a null or a var-width attribute.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 0; i < attnum; i++)
|
for (i = 0; i < attnum; i++)
|
||||||
|
@ -597,15 +596,13 @@ heap_getsysattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the attribute number is 0, then we are supposed to
|
* If the attribute number is 0, then we are supposed to return
|
||||||
* return the entire tuple as a row-type Datum. (Using zero
|
* the entire tuple as a row-type Datum. (Using zero for this
|
||||||
* for this purpose is unclean since it risks confusion with
|
* purpose is unclean since it risks confusion with "invalid attr"
|
||||||
* "invalid attr" result codes, but it's not worth changing
|
* result codes, but it's not worth changing now.)
|
||||||
* now.)
|
|
||||||
*
|
*
|
||||||
* We have to make a copy of the tuple so we can safely insert
|
* We have to make a copy of the tuple so we can safely insert the
|
||||||
* the Datum overhead fields, which are not set in on-disk
|
* Datum overhead fields, which are not set in on-disk tuples.
|
||||||
* tuples.
|
|
||||||
*/
|
*/
|
||||||
case InvalidAttrNumber:
|
case InvalidAttrNumber:
|
||||||
{
|
{
|
||||||
|
@ -708,15 +705,15 @@ heap_form_tuple(TupleDesc tupleDescriptor,
|
||||||
numberOfAttributes, MaxTupleAttributeNumber)));
|
numberOfAttributes, MaxTupleAttributeNumber)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for nulls and embedded tuples; expand any toasted attributes
|
* Check for nulls and embedded tuples; expand any toasted attributes in
|
||||||
* in embedded tuples. This preserves the invariant that toasting can
|
* embedded tuples. This preserves the invariant that toasting can only
|
||||||
* only go one level deep.
|
* go one level deep.
|
||||||
*
|
*
|
||||||
* We can skip calling toast_flatten_tuple_attribute() if the attribute
|
* We can skip calling toast_flatten_tuple_attribute() if the attribute
|
||||||
* couldn't possibly be of composite type. All composite datums are
|
* couldn't possibly be of composite type. All composite datums are
|
||||||
* varlena and have alignment 'd'; furthermore they aren't arrays.
|
* varlena and have alignment 'd'; furthermore they aren't arrays. Also,
|
||||||
* Also, if an attribute is already toasted, it must have been sent to
|
* if an attribute is already toasted, it must have been sent to disk
|
||||||
* disk already and so cannot contain toasted attributes.
|
* already and so cannot contain toasted attributes.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numberOfAttributes; i++)
|
for (i = 0; i < numberOfAttributes; i++)
|
||||||
{
|
{
|
||||||
|
@ -757,8 +754,8 @@ heap_form_tuple(TupleDesc tupleDescriptor,
|
||||||
tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
|
tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And fill in the information. Note we fill the Datum fields even
|
* And fill in the information. Note we fill the Datum fields even though
|
||||||
* though this tuple may never become a Datum.
|
* this tuple may never become a Datum.
|
||||||
*/
|
*/
|
||||||
tuple->t_len = len;
|
tuple->t_len = len;
|
||||||
ItemPointerSetInvalid(&(tuple->t_self));
|
ItemPointerSetInvalid(&(tuple->t_self));
|
||||||
|
@ -816,15 +813,15 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
||||||
numberOfAttributes, MaxTupleAttributeNumber)));
|
numberOfAttributes, MaxTupleAttributeNumber)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for nulls and embedded tuples; expand any toasted attributes
|
* Check for nulls and embedded tuples; expand any toasted attributes in
|
||||||
* in embedded tuples. This preserves the invariant that toasting can
|
* embedded tuples. This preserves the invariant that toasting can only
|
||||||
* only go one level deep.
|
* go one level deep.
|
||||||
*
|
*
|
||||||
* We can skip calling toast_flatten_tuple_attribute() if the attribute
|
* We can skip calling toast_flatten_tuple_attribute() if the attribute
|
||||||
* couldn't possibly be of composite type. All composite datums are
|
* couldn't possibly be of composite type. All composite datums are
|
||||||
* varlena and have alignment 'd'; furthermore they aren't arrays.
|
* varlena and have alignment 'd'; furthermore they aren't arrays. Also,
|
||||||
* Also, if an attribute is already toasted, it must have been sent to
|
* if an attribute is already toasted, it must have been sent to disk
|
||||||
* disk already and so cannot contain toasted attributes.
|
* already and so cannot contain toasted attributes.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numberOfAttributes; i++)
|
for (i = 0; i < numberOfAttributes; i++)
|
||||||
{
|
{
|
||||||
|
@ -865,8 +862,8 @@ heap_formtuple(TupleDesc tupleDescriptor,
|
||||||
tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
|
tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* And fill in the information. Note we fill the Datum fields even
|
* And fill in the information. Note we fill the Datum fields even though
|
||||||
* though this tuple may never become a Datum.
|
* this tuple may never become a Datum.
|
||||||
*/
|
*/
|
||||||
tuple->t_len = len;
|
tuple->t_len = len;
|
||||||
ItemPointerSetInvalid(&(tuple->t_self));
|
ItemPointerSetInvalid(&(tuple->t_self));
|
||||||
|
@ -917,15 +914,15 @@ heap_modify_tuple(HeapTuple tuple,
|
||||||
HeapTuple newTuple;
|
HeapTuple newTuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate and fill values and isnull arrays from either the tuple or
|
* allocate and fill values and isnull arrays from either the tuple or the
|
||||||
* the repl information, as appropriate.
|
* repl information, as appropriate.
|
||||||
*
|
*
|
||||||
* NOTE: it's debatable whether to use heap_deform_tuple() here or just
|
* NOTE: it's debatable whether to use heap_deform_tuple() here or just
|
||||||
* heap_getattr() only the non-replaced colums. The latter could win
|
* heap_getattr() only the non-replaced colums. The latter could win if
|
||||||
* if there are many replaced columns and few non-replaced ones.
|
* there are many replaced columns and few non-replaced ones. However,
|
||||||
* However, heap_deform_tuple costs only O(N) while the heap_getattr
|
* heap_deform_tuple costs only O(N) while the heap_getattr way would cost
|
||||||
* way would cost O(N^2) if there are many non-replaced columns, so it
|
* O(N^2) if there are many non-replaced columns, so it seems better to
|
||||||
* seems better to err on the side of linear cost.
|
* err on the side of linear cost.
|
||||||
*/
|
*/
|
||||||
values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
|
values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
|
||||||
isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
|
isnull = (bool *) palloc(numberOfAttributes * sizeof(bool));
|
||||||
|
@ -950,8 +947,8 @@ heap_modify_tuple(HeapTuple tuple,
|
||||||
pfree(isnull);
|
pfree(isnull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copy the identification info of the old tuple: t_ctid, t_self, and
|
* copy the identification info of the old tuple: t_ctid, t_self, and OID
|
||||||
* OID (if any)
|
* (if any)
|
||||||
*/
|
*/
|
||||||
newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
|
newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
|
||||||
newTuple->t_self = tuple->t_self;
|
newTuple->t_self = tuple->t_self;
|
||||||
|
@ -986,15 +983,15 @@ heap_modifytuple(HeapTuple tuple,
|
||||||
HeapTuple newTuple;
|
HeapTuple newTuple;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* allocate and fill values and nulls arrays from either the tuple or
|
* allocate and fill values and nulls arrays from either the tuple or the
|
||||||
* the repl information, as appropriate.
|
* repl information, as appropriate.
|
||||||
*
|
*
|
||||||
* NOTE: it's debatable whether to use heap_deformtuple() here or just
|
* NOTE: it's debatable whether to use heap_deformtuple() here or just
|
||||||
* heap_getattr() only the non-replaced colums. The latter could win
|
* heap_getattr() only the non-replaced colums. The latter could win if
|
||||||
* if there are many replaced columns and few non-replaced ones.
|
* there are many replaced columns and few non-replaced ones. However,
|
||||||
* However, heap_deformtuple costs only O(N) while the heap_getattr
|
* heap_deformtuple costs only O(N) while the heap_getattr way would cost
|
||||||
* way would cost O(N^2) if there are many non-replaced columns, so it
|
* O(N^2) if there are many non-replaced columns, so it seems better to
|
||||||
* seems better to err on the side of linear cost.
|
* err on the side of linear cost.
|
||||||
*/
|
*/
|
||||||
values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
|
values = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
|
||||||
nulls = (char *) palloc(numberOfAttributes * sizeof(char));
|
nulls = (char *) palloc(numberOfAttributes * sizeof(char));
|
||||||
|
@ -1022,8 +1019,8 @@ heap_modifytuple(HeapTuple tuple,
|
||||||
pfree(nulls);
|
pfree(nulls);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* copy the identification info of the old tuple: t_ctid, t_self, and
|
* copy the identification info of the old tuple: t_ctid, t_self, and OID
|
||||||
* OID (if any)
|
* (if any)
|
||||||
*/
|
*/
|
||||||
newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
|
newTuple->t_data->t_ctid = tuple->t_data->t_ctid;
|
||||||
newTuple->t_self = tuple->t_self;
|
newTuple->t_self = tuple->t_self;
|
||||||
|
@ -1068,9 +1065,9 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
|
||||||
natts = tup->t_natts;
|
natts = tup->t_natts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In inheritance situations, it is possible that the given tuple
|
* In inheritance situations, it is possible that the given tuple actually
|
||||||
* actually has more fields than the caller is expecting. Don't run
|
* has more fields than the caller is expecting. Don't run off the end of
|
||||||
* off the end of the caller's arrays.
|
* the caller's arrays.
|
||||||
*/
|
*/
|
||||||
natts = Min(natts, tdesc_natts);
|
natts = Min(natts, tdesc_natts);
|
||||||
|
|
||||||
|
@ -1161,9 +1158,9 @@ heap_deformtuple(HeapTuple tuple,
|
||||||
natts = tup->t_natts;
|
natts = tup->t_natts;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In inheritance situations, it is possible that the given tuple
|
* In inheritance situations, it is possible that the given tuple actually
|
||||||
* actually has more fields than the caller is expecting. Don't run
|
* has more fields than the caller is expecting. Don't run off the end of
|
||||||
* off the end of the caller's arrays.
|
* the caller's arrays.
|
||||||
*/
|
*/
|
||||||
natts = Min(natts, tdesc_natts);
|
natts = Min(natts, tdesc_natts);
|
||||||
|
|
||||||
|
@ -1242,8 +1239,8 @@ slot_deform_tuple(TupleTableSlot *slot, int natts)
|
||||||
bool slow; /* can we use/set attcacheoff? */
|
bool slow; /* can we use/set attcacheoff? */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the first call for this tuple, and initialize or
|
* Check whether the first call for this tuple, and initialize or restore
|
||||||
* restore loop state.
|
* loop state.
|
||||||
*/
|
*/
|
||||||
attnum = slot->tts_nvalid;
|
attnum = slot->tts_nvalid;
|
||||||
if (attnum == 0)
|
if (attnum == 0)
|
||||||
|
@ -1349,8 +1346,8 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* otherwise we had better have a physical tuple (tts_nvalid should
|
* otherwise we had better have a physical tuple (tts_nvalid should equal
|
||||||
* equal natts in all virtual-tuple cases)
|
* natts in all virtual-tuple cases)
|
||||||
*/
|
*/
|
||||||
if (tuple == NULL) /* internal error */
|
if (tuple == NULL) /* internal error */
|
||||||
elog(ERROR, "cannot extract attribute from empty tuple slot");
|
elog(ERROR, "cannot extract attribute from empty tuple slot");
|
||||||
|
@ -1358,9 +1355,9 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
|
||||||
/*
|
/*
|
||||||
* return NULL if attnum is out of range according to the tuple
|
* return NULL if attnum is out of range according to the tuple
|
||||||
*
|
*
|
||||||
* (We have to check this separately because of various inheritance
|
* (We have to check this separately because of various inheritance and
|
||||||
* and table-alteration scenarios: the tuple could be either longer
|
* table-alteration scenarios: the tuple could be either longer or shorter
|
||||||
* or shorter than the tupdesc.)
|
* than the tupdesc.)
|
||||||
*/
|
*/
|
||||||
tup = tuple->t_data;
|
tup = tuple->t_data;
|
||||||
if (attnum > tup->t_natts)
|
if (attnum > tup->t_natts)
|
||||||
|
@ -1379,10 +1376,9 @@ slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the attribute's column has been dropped, we force a NULL
|
* If the attribute's column has been dropped, we force a NULL result.
|
||||||
* result. This case should not happen in normal use, but it could
|
* This case should not happen in normal use, but it could happen if we
|
||||||
* happen if we are executing a plan cached before the column was
|
* are executing a plan cached before the column was dropped.
|
||||||
* dropped.
|
|
||||||
*/
|
*/
|
||||||
if (tupleDesc->attrs[attnum - 1]->attisdropped)
|
if (tupleDesc->attrs[attnum - 1]->attisdropped)
|
||||||
{
|
{
|
||||||
|
@ -1420,8 +1416,8 @@ slot_getallattrs(TupleTableSlot *slot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* otherwise we had better have a physical tuple (tts_nvalid should
|
* otherwise we had better have a physical tuple (tts_nvalid should equal
|
||||||
* equal natts in all virtual-tuple cases)
|
* natts in all virtual-tuple cases)
|
||||||
*/
|
*/
|
||||||
tuple = slot->tts_tuple;
|
tuple = slot->tts_tuple;
|
||||||
if (tuple == NULL) /* internal error */
|
if (tuple == NULL) /* internal error */
|
||||||
|
@ -1467,8 +1463,8 @@ slot_getsomeattrs(TupleTableSlot *slot, int attnum)
|
||||||
elog(ERROR, "invalid attribute number %d", attnum);
|
elog(ERROR, "invalid attribute number %d", attnum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* otherwise we had better have a physical tuple (tts_nvalid should
|
* otherwise we had better have a physical tuple (tts_nvalid should equal
|
||||||
* equal natts in all virtual-tuple cases)
|
* natts in all virtual-tuple cases)
|
||||||
*/
|
*/
|
||||||
tuple = slot->tts_tuple;
|
tuple = slot->tts_tuple;
|
||||||
if (tuple == NULL) /* internal error */
|
if (tuple == NULL) /* internal error */
|
||||||
|
@ -1528,8 +1524,8 @@ slot_attisnull(TupleTableSlot *slot, int attnum)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* otherwise we had better have a physical tuple (tts_nvalid should
|
* otherwise we had better have a physical tuple (tts_nvalid should equal
|
||||||
* equal natts in all virtual-tuple cases)
|
* natts in all virtual-tuple cases)
|
||||||
*/
|
*/
|
||||||
if (tuple == NULL) /* internal error */
|
if (tuple == NULL) /* internal error */
|
||||||
elog(ERROR, "cannot extract attribute from empty tuple slot");
|
elog(ERROR, "cannot extract attribute from empty tuple slot");
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.74 2005/03/27 18:38:26 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.75 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -70,8 +70,8 @@ index_form_tuple(TupleDesc tupleDescriptor,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If value is stored EXTERNAL, must fetch it so we are not
|
* If value is stored EXTERNAL, must fetch it so we are not depending
|
||||||
* depending on outside storage. This should be improved someday.
|
* on outside storage. This should be improved someday.
|
||||||
*/
|
*/
|
||||||
if (VARATT_IS_EXTERNAL(values[i]))
|
if (VARATT_IS_EXTERNAL(values[i]))
|
||||||
{
|
{
|
||||||
|
@ -82,8 +82,8 @@ index_form_tuple(TupleDesc tupleDescriptor,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If value is above size target, and is of a compressible
|
* If value is above size target, and is of a compressible datatype,
|
||||||
* datatype, try to compress it in-line.
|
* try to compress it in-line.
|
||||||
*/
|
*/
|
||||||
if (VARATT_SIZE(untoasted_values[i]) > TOAST_INDEX_TARGET &&
|
if (VARATT_SIZE(untoasted_values[i]) > TOAST_INDEX_TARGET &&
|
||||||
!VARATT_IS_EXTENDED(untoasted_values[i]) &&
|
!VARATT_IS_EXTENDED(untoasted_values[i]) &&
|
||||||
|
@ -149,16 +149,16 @@ index_form_tuple(TupleDesc tupleDescriptor,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do this because heap_fill_tuple wants to initialize a "tupmask"
|
* We do this because heap_fill_tuple wants to initialize a "tupmask"
|
||||||
* which is used for HeapTuples, but we want an indextuple infomask.
|
* which is used for HeapTuples, but we want an indextuple infomask. The
|
||||||
* The only relevant info is the "has variable attributes" field.
|
* only relevant info is the "has variable attributes" field. We have
|
||||||
* We have already set the hasnull bit above.
|
* already set the hasnull bit above.
|
||||||
*/
|
*/
|
||||||
if (tupmask & HEAP_HASVARWIDTH)
|
if (tupmask & HEAP_HASVARWIDTH)
|
||||||
infomask |= INDEX_VAR_MASK;
|
infomask |= INDEX_VAR_MASK;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Here we make sure that the size will fit in the field reserved for
|
* Here we make sure that the size will fit in the field reserved for it
|
||||||
* it in t_info.
|
* in t_info.
|
||||||
*/
|
*/
|
||||||
if ((size & INDEX_SIZE_MASK) != size)
|
if ((size & INDEX_SIZE_MASK) != size)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -322,10 +322,9 @@ nocache_index_getattr(IndexTuple tup,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If slow is false, and we got here, we know that we have a tuple
|
* If slow is false, and we got here, we know that we have a tuple with no
|
||||||
* with no nulls or var-widths before the target attribute. If
|
* nulls or var-widths before the target attribute. If possible, we also
|
||||||
* possible, we also want to initialize the remainder of the attribute
|
* want to initialize the remainder of the attribute cached offset values.
|
||||||
* cached offset values.
|
|
||||||
*/
|
*/
|
||||||
if (!slow)
|
if (!slow)
|
||||||
{
|
{
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.91 2005/06/22 17:45:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.92 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -78,9 +78,9 @@ printtup_create_DR(CommandDest dest, Portal portal)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* In protocol 2.0 the Bind message does not exist, so there is no
|
* In protocol 2.0 the Bind message does not exist, so there is no way
|
||||||
* way for the columns to have different print formats; it's
|
* for the columns to have different print formats; it's sufficient to
|
||||||
* sufficient to look at the first one.
|
* look at the first one.
|
||||||
*/
|
*/
|
||||||
if (portal->formats && portal->formats[0] != 0)
|
if (portal->formats && portal->formats[0] != 0)
|
||||||
self->pub.receiveSlot = printtup_internal_20;
|
self->pub.receiveSlot = printtup_internal_20;
|
||||||
|
@ -113,8 +113,7 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
||||||
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
|
if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Send portal name to frontend (obsolete cruft, gone in proto
|
* Send portal name to frontend (obsolete cruft, gone in proto 3.0)
|
||||||
* 3.0)
|
|
||||||
*
|
*
|
||||||
* If portal name not specified, use "blank" portal.
|
* If portal name not specified, use "blank" portal.
|
||||||
*/
|
*/
|
||||||
|
@ -127,8 +126,8 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is a retrieve, and we are supposed to emit row
|
* If this is a retrieve, and we are supposed to emit row descriptions,
|
||||||
* descriptions, then we send back the tuple descriptor of the tuples.
|
* then we send back the tuple descriptor of the tuples.
|
||||||
*/
|
*/
|
||||||
if (operation == CMD_SELECT && myState->sendDescrip)
|
if (operation == CMD_SELECT && myState->sendDescrip)
|
||||||
SendRowDescriptionMessage(typeinfo,
|
SendRowDescriptionMessage(typeinfo,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.111 2005/04/14 22:34:48 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.112 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* some of the executor utility code such as "ExecTypeFromTL" should be
|
* some of the executor utility code such as "ExecTypeFromTL" should be
|
||||||
|
@ -49,10 +49,10 @@ CreateTemplateTupleDesc(int natts, bool hasoid)
|
||||||
* Allocate enough memory for the tuple descriptor, including the
|
* Allocate enough memory for the tuple descriptor, including the
|
||||||
* attribute rows, and set up the attribute row pointers.
|
* attribute rows, and set up the attribute row pointers.
|
||||||
*
|
*
|
||||||
* Note: we assume that sizeof(struct tupleDesc) is a multiple of
|
* Note: we assume that sizeof(struct tupleDesc) is a multiple of the struct
|
||||||
* the struct pointer alignment requirement, and hence we don't need
|
* pointer alignment requirement, and hence we don't need to insert
|
||||||
* to insert alignment padding between the struct and the array of
|
* alignment padding between the struct and the array of attribute row
|
||||||
* attribute row pointers.
|
* pointers.
|
||||||
*/
|
*/
|
||||||
attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);
|
attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);
|
||||||
attroffset = MAXALIGN(attroffset);
|
attroffset = MAXALIGN(attroffset);
|
||||||
|
@ -273,16 +273,16 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||||
Form_pg_attribute attr2 = tupdesc2->attrs[i];
|
Form_pg_attribute attr2 = tupdesc2->attrs[i];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not need to check every single field here: we can
|
* We do not need to check every single field here: we can disregard
|
||||||
* disregard attrelid and attnum (which were used to place the row
|
* attrelid and attnum (which were used to place the row in the attrs
|
||||||
* in the attrs array in the first place). It might look like we
|
* array in the first place). It might look like we could dispense
|
||||||
* could dispense with checking attlen/attbyval/attalign, since these
|
* with checking attlen/attbyval/attalign, since these are derived
|
||||||
* are derived from atttypid; but in the case of dropped columns
|
* from atttypid; but in the case of dropped columns we must check
|
||||||
* we must check them (since atttypid will be zero for all dropped
|
* them (since atttypid will be zero for all dropped columns) and in
|
||||||
* columns) and in general it seems safer to check them always.
|
* general it seems safer to check them always.
|
||||||
*
|
*
|
||||||
* attcacheoff must NOT be checked since it's possibly not set
|
* attcacheoff must NOT be checked since it's possibly not set in both
|
||||||
* in both copies.
|
* copies.
|
||||||
*/
|
*/
|
||||||
if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
|
if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
|
||||||
return false;
|
return false;
|
||||||
|
@ -332,9 +332,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||||
AttrDefault *defval2 = constr2->defval;
|
AttrDefault *defval2 = constr2->defval;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't assume that the items are always read from the
|
* We can't assume that the items are always read from the system
|
||||||
* system catalogs in the same order; so use the adnum field
|
* catalogs in the same order; so use the adnum field to identify
|
||||||
* to identify the matching item to compare.
|
* the matching item to compare.
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < n; defval2++, j++)
|
for (j = 0; j < n; defval2++, j++)
|
||||||
{
|
{
|
||||||
|
@ -355,9 +355,9 @@ equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
||||||
ConstrCheck *check2 = constr2->check;
|
ConstrCheck *check2 = constr2->check;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Similarly, don't assume that the checks are always read in
|
* Similarly, don't assume that the checks are always read in the
|
||||||
* the same order; match them up by name and contents. (The
|
* same order; match them up by name and contents. (The name
|
||||||
* name *should* be unique, but...)
|
* *should* be unique, but...)
|
||||||
*/
|
*/
|
||||||
for (j = 0; j < n; check2++, j++)
|
for (j = 0; j < n; check2++, j++)
|
||||||
{
|
{
|
||||||
|
@ -407,8 +407,8 @@ TupleDescInitEntry(TupleDesc desc,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: attributeName can be NULL, because the planner doesn't always
|
* Note: attributeName can be NULL, because the planner doesn't always
|
||||||
* fill in valid resname values in targetlists, particularly for
|
* fill in valid resname values in targetlists, particularly for resjunk
|
||||||
* resjunk attributes.
|
* attributes.
|
||||||
*/
|
*/
|
||||||
if (attributeName != NULL)
|
if (attributeName != NULL)
|
||||||
namestrcpy(&(att->attname), attributeName);
|
namestrcpy(&(att->attname), attributeName);
|
||||||
|
@ -482,8 +482,8 @@ BuildDescForRelation(List *schema)
|
||||||
ColumnDef *entry = lfirst(l);
|
ColumnDef *entry = lfirst(l);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* for each entry in the list, get the name and type information
|
* for each entry in the list, get the name and type information from
|
||||||
* from the list and have TupleDescInitEntry fill in the attribute
|
* the list and have TupleDescInitEntry fill in the attribute
|
||||||
* information we need.
|
* information we need.
|
||||||
*/
|
*/
|
||||||
attnum++;
|
attnum++;
|
||||||
|
@ -508,8 +508,8 @@ BuildDescForRelation(List *schema)
|
||||||
desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
|
desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note we copy only pre-cooked default expressions. Digestion of
|
* Note we copy only pre-cooked default expressions. Digestion of raw
|
||||||
* raw ones is someone else's problem.
|
* ones is someone else's problem.
|
||||||
*/
|
*/
|
||||||
if (entry->cooked_default != NULL)
|
if (entry->cooked_default != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.2 2005/09/22 20:44:36 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/gist/gistproc.c,v 1.3 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.80 2005/06/06 17:01:21 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hash.c,v 1.81 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* This file contains only the public interface routines.
|
* This file contains only the public interface routines.
|
||||||
|
@ -55,8 +55,8 @@ hashbuild(PG_FUNCTION_ARGS)
|
||||||
HashBuildState buildstate;
|
HashBuildState buildstate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We expect to be called exactly once for any index relation. If
|
* We expect to be called exactly once for any index relation. If that's
|
||||||
* that's not the case, big trouble's what we have.
|
* not the case, big trouble's what we have.
|
||||||
*/
|
*/
|
||||||
if (RelationGetNumberOfBlocks(index) != 0)
|
if (RelationGetNumberOfBlocks(index) != 0)
|
||||||
elog(ERROR, "index \"%s\" already contains data",
|
elog(ERROR, "index \"%s\" already contains data",
|
||||||
|
@ -141,12 +141,12 @@ hashinsert(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the single index key is null, we don't insert it into the index.
|
* If the single index key is null, we don't insert it into the index.
|
||||||
* Hash tables support scans on '='. Relational algebra says that A =
|
* Hash tables support scans on '='. Relational algebra says that A = B
|
||||||
* B returns null if either A or B is null. This means that no
|
* returns null if either A or B is null. This means that no
|
||||||
* qualification used in an index scan could ever return true on a
|
* qualification used in an index scan could ever return true on a null
|
||||||
* null attribute. It also means that indices can't be used by ISNULL
|
* attribute. It also means that indices can't be used by ISNULL or
|
||||||
* or NOTNULL scans, but that's an artifact of the strategy map
|
* NOTNULL scans, but that's an artifact of the strategy map architecture
|
||||||
* architecture chosen in 1986, not of the way nulls are handled here.
|
* chosen in 1986, not of the way nulls are handled here.
|
||||||
*/
|
*/
|
||||||
if (IndexTupleHasNulls(itup))
|
if (IndexTupleHasNulls(itup))
|
||||||
{
|
{
|
||||||
|
@ -180,16 +180,16 @@ hashgettuple(PG_FUNCTION_ARGS)
|
||||||
bool res;
|
bool res;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We hold pin but not lock on current buffer while outside the hash
|
* We hold pin but not lock on current buffer while outside the hash AM.
|
||||||
* AM. Reacquire the read lock here.
|
* Reacquire the read lock here.
|
||||||
*/
|
*/
|
||||||
if (BufferIsValid(so->hashso_curbuf))
|
if (BufferIsValid(so->hashso_curbuf))
|
||||||
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);
|
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've already initialized this scan, we can just advance it in
|
* If we've already initialized this scan, we can just advance it in the
|
||||||
* the appropriate direction. If we haven't done so yet, we call a
|
* appropriate direction. If we haven't done so yet, we call a routine to
|
||||||
* routine to get the first item in the scan.
|
* get the first item in the scan.
|
||||||
*/
|
*/
|
||||||
if (ItemPointerIsValid(&(scan->currentItemData)))
|
if (ItemPointerIsValid(&(scan->currentItemData)))
|
||||||
{
|
{
|
||||||
|
@ -199,17 +199,16 @@ hashgettuple(PG_FUNCTION_ARGS)
|
||||||
if (scan->kill_prior_tuple)
|
if (scan->kill_prior_tuple)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Yes, so mark it by setting the LP_DELETE bit in the item
|
* Yes, so mark it by setting the LP_DELETE bit in the item flags.
|
||||||
* flags.
|
|
||||||
*/
|
*/
|
||||||
offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
|
offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
|
||||||
page = BufferGetPage(so->hashso_curbuf);
|
page = BufferGetPage(so->hashso_curbuf);
|
||||||
PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
|
PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since this can be redone later if needed, it's treated the
|
* Since this can be redone later if needed, it's treated the same
|
||||||
* same as a commit-hint-bit status update for heap tuples: we
|
* as a commit-hint-bit status update for heap tuples: we mark the
|
||||||
* mark the buffer dirty but don't make a WAL log entry.
|
* buffer dirty but don't make a WAL log entry.
|
||||||
*/
|
*/
|
||||||
SetBufferCommitInfoNeedsSave(so->hashso_curbuf);
|
SetBufferCommitInfoNeedsSave(so->hashso_curbuf);
|
||||||
}
|
}
|
||||||
|
@ -265,8 +264,8 @@ hashgetmulti(PG_FUNCTION_ARGS)
|
||||||
int32 ntids = 0;
|
int32 ntids = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We hold pin but not lock on current buffer while outside the hash
|
* We hold pin but not lock on current buffer while outside the hash AM.
|
||||||
* AM. Reacquire the read lock here.
|
* Reacquire the read lock here.
|
||||||
*/
|
*/
|
||||||
if (BufferIsValid(so->hashso_curbuf))
|
if (BufferIsValid(so->hashso_curbuf))
|
||||||
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);
|
_hash_chgbufaccess(rel, so->hashso_curbuf, HASH_NOLOCK, HASH_READ);
|
||||||
|
@ -280,6 +279,7 @@ hashgetmulti(PG_FUNCTION_ARGS)
|
||||||
res = _hash_next(scan, ForwardScanDirection);
|
res = _hash_next(scan, ForwardScanDirection);
|
||||||
else
|
else
|
||||||
res = _hash_first(scan, ForwardScanDirection);
|
res = _hash_first(scan, ForwardScanDirection);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip killed tuples if asked to.
|
* Skip killed tuples if asked to.
|
||||||
*/
|
*/
|
||||||
|
@ -505,12 +505,12 @@ hashbulkdelete(PG_FUNCTION_ARGS)
|
||||||
num_index_tuples = 0;
|
num_index_tuples = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Read the metapage to fetch original bucket and tuple counts. Also,
|
* Read the metapage to fetch original bucket and tuple counts. Also, we
|
||||||
* we keep a copy of the last-seen metapage so that we can use its
|
* keep a copy of the last-seen metapage so that we can use its
|
||||||
* hashm_spares[] values to compute bucket page addresses. This is a
|
* hashm_spares[] values to compute bucket page addresses. This is a bit
|
||||||
* bit hokey but perfectly safe, since the interesting entries in the
|
* hokey but perfectly safe, since the interesting entries in the spares
|
||||||
* spares array cannot change under us; and it beats rereading the
|
* array cannot change under us; and it beats rereading the metapage for
|
||||||
* metapage for each bucket.
|
* each bucket.
|
||||||
*/
|
*/
|
||||||
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
|
metabuf = _hash_getbuf(rel, HASH_METAPAGE, HASH_READ);
|
||||||
metap = (HashMetaPage) BufferGetPage(metabuf);
|
metap = (HashMetaPage) BufferGetPage(metabuf);
|
||||||
|
@ -641,8 +641,7 @@ loop_top:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Otherwise, our count is untrustworthy since we may have
|
* Otherwise, our count is untrustworthy since we may have
|
||||||
* double-scanned tuples in split buckets. Proceed by
|
* double-scanned tuples in split buckets. Proceed by dead-reckoning.
|
||||||
* dead-reckoning.
|
|
||||||
*/
|
*/
|
||||||
if (metap->hashm_ntuples > tuples_removed)
|
if (metap->hashm_ntuples > tuples_removed)
|
||||||
metap->hashm_ntuples -= tuples_removed;
|
metap->hashm_ntuples -= tuples_removed;
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.44 2005/05/25 21:40:40 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashfunc.c,v 1.45 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* These functions are stored in pg_amproc. For each operator class
|
* These functions are stored in pg_amproc. For each operator class
|
||||||
|
@ -46,11 +46,11 @@ hashint8(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The idea here is to produce a hash value compatible with the values
|
* The idea here is to produce a hash value compatible with the values
|
||||||
* produced by hashint4 and hashint2 for logically equivalent inputs;
|
* produced by hashint4 and hashint2 for logically equivalent inputs; this
|
||||||
* this is necessary if we ever hope to support cross-type hash joins
|
* is necessary if we ever hope to support cross-type hash joins across
|
||||||
* across these input types. Since all three types are signed, we can
|
* these input types. Since all three types are signed, we can xor the
|
||||||
* xor the high half of the int8 value if the sign is positive, or the
|
* high half of the int8 value if the sign is positive, or the complement
|
||||||
* complement of the high half when the sign is negative.
|
* of the high half when the sign is negative.
|
||||||
*/
|
*/
|
||||||
#ifndef INT64_IS_BUSTED
|
#ifndef INT64_IS_BUSTED
|
||||||
int64 val = PG_GETARG_INT64(0);
|
int64 val = PG_GETARG_INT64(0);
|
||||||
|
@ -78,9 +78,9 @@ hashfloat4(PG_FUNCTION_ARGS)
|
||||||
float4 key = PG_GETARG_FLOAT4(0);
|
float4 key = PG_GETARG_FLOAT4(0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On IEEE-float machines, minus zero and zero have different bit
|
* On IEEE-float machines, minus zero and zero have different bit patterns
|
||||||
* patterns but should compare as equal. We must ensure that they
|
* but should compare as equal. We must ensure that they have the same
|
||||||
* have the same hash value, which is most easily done this way:
|
* hash value, which is most easily done this way:
|
||||||
*/
|
*/
|
||||||
if (key == (float4) 0)
|
if (key == (float4) 0)
|
||||||
PG_RETURN_UINT32(0);
|
PG_RETURN_UINT32(0);
|
||||||
|
@ -94,9 +94,9 @@ hashfloat8(PG_FUNCTION_ARGS)
|
||||||
float8 key = PG_GETARG_FLOAT8(0);
|
float8 key = PG_GETARG_FLOAT8(0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On IEEE-float machines, minus zero and zero have different bit
|
* On IEEE-float machines, minus zero and zero have different bit patterns
|
||||||
* patterns but should compare as equal. We must ensure that they
|
* but should compare as equal. We must ensure that they have the same
|
||||||
* have the same hash value, which is most easily done this way:
|
* hash value, which is most easily done this way:
|
||||||
*/
|
*/
|
||||||
if (key == (float8) 0)
|
if (key == (float8) 0)
|
||||||
PG_RETURN_UINT32(0);
|
PG_RETURN_UINT32(0);
|
||||||
|
@ -126,8 +126,7 @@ hashname(PG_FUNCTION_ARGS)
|
||||||
char *key = NameStr(*PG_GETARG_NAME(0));
|
char *key = NameStr(*PG_GETARG_NAME(0));
|
||||||
int keylen = strlen(key);
|
int keylen = strlen(key);
|
||||||
|
|
||||||
Assert(keylen < NAMEDATALEN); /* else it's not truncated
|
Assert(keylen < NAMEDATALEN); /* else it's not truncated correctly */
|
||||||
* correctly */
|
|
||||||
|
|
||||||
return hash_any((unsigned char *) key, keylen);
|
return hash_any((unsigned char *) key, keylen);
|
||||||
}
|
}
|
||||||
|
@ -139,8 +138,8 @@ hashtext(PG_FUNCTION_ARGS)
|
||||||
Datum result;
|
Datum result;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: this is currently identical in behavior to hashvarlena, but
|
* Note: this is currently identical in behavior to hashvarlena, but it
|
||||||
* it seems likely that we may need to do something different in non-C
|
* seems likely that we may need to do something different in non-C
|
||||||
* locales. (See also hashbpchar, if so.)
|
* locales. (See also hashbpchar, if so.)
|
||||||
*/
|
*/
|
||||||
result = hash_any((unsigned char *) VARDATA(key),
|
result = hash_any((unsigned char *) VARDATA(key),
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.37 2005/08/10 21:36:45 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashinsert.c,v 1.38 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -50,8 +50,8 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||||
bool isnull;
|
bool isnull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the hash key for the item. We do this first so as not to
|
* Compute the hash key for the item. We do this first so as not to need
|
||||||
* need to hold any locks while running the hash function.
|
* to hold any locks while running the hash function.
|
||||||
*/
|
*/
|
||||||
itup = &(hitem->hash_itup);
|
itup = &(hitem->hash_itup);
|
||||||
if (rel->rd_rel->relnatts != 1)
|
if (rel->rd_rel->relnatts != 1)
|
||||||
|
@ -64,12 +64,12 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||||
itemsz = IndexTupleDSize(hitem->hash_itup)
|
itemsz = IndexTupleDSize(hitem->hash_itup)
|
||||||
+ (sizeof(HashItemData) - sizeof(IndexTupleData));
|
+ (sizeof(HashItemData) - sizeof(IndexTupleData));
|
||||||
|
|
||||||
itemsz = MAXALIGN(itemsz); /* be safe, PageAddItem will do this but
|
itemsz = MAXALIGN(itemsz); /* be safe, PageAddItem will do this but we
|
||||||
* we need to be consistent */
|
* need to be consistent */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire shared split lock so we can compute the target bucket
|
* Acquire shared split lock so we can compute the target bucket safely
|
||||||
* safely (see README).
|
* (see README).
|
||||||
*/
|
*/
|
||||||
_hash_getlock(rel, 0, HASH_SHARE);
|
_hash_getlock(rel, 0, HASH_SHARE);
|
||||||
|
|
||||||
|
@ -79,9 +79,9 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||||
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
|
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the item can fit on a hash page at all. (Eventually,
|
* Check whether the item can fit on a hash page at all. (Eventually, we
|
||||||
* we ought to try to apply TOAST methods if not.) Note that at this
|
* ought to try to apply TOAST methods if not.) Note that at this point,
|
||||||
* point, itemsz doesn't include the ItemId.
|
* itemsz doesn't include the ItemId.
|
||||||
*/
|
*/
|
||||||
if (itemsz > HashMaxItemSize((Page) metap))
|
if (itemsz > HashMaxItemSize((Page) metap))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -105,8 +105,7 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||||
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
|
_hash_chgbufaccess(rel, metabuf, HASH_READ, HASH_NOLOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire share lock on target bucket; then we can release split
|
* Acquire share lock on target bucket; then we can release split lock.
|
||||||
* lock.
|
|
||||||
*/
|
*/
|
||||||
_hash_getlock(rel, blkno, HASH_SHARE);
|
_hash_getlock(rel, blkno, HASH_SHARE);
|
||||||
|
|
||||||
|
@ -130,8 +129,8 @@ _hash_doinsert(Relation rel, HashItem hitem)
|
||||||
if (BlockNumberIsValid(nextblkno))
|
if (BlockNumberIsValid(nextblkno))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* ovfl page exists; go get it. if it doesn't have room,
|
* ovfl page exists; go get it. if it doesn't have room, we'll
|
||||||
* we'll find out next pass through the loop test above.
|
* find out next pass through the loop test above.
|
||||||
*/
|
*/
|
||||||
_hash_relbuf(rel, buf);
|
_hash_relbuf(rel, buf);
|
||||||
buf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
|
buf = _hash_getbuf(rel, nextblkno, HASH_WRITE);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.46 2005/05/11 01:26:01 neilc Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashovfl.c,v 1.47 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Overflow pages look like ordinary relation pages.
|
* Overflow pages look like ordinary relation pages.
|
||||||
|
@ -44,8 +44,8 @@ bitno_to_blkno(HashMetaPage metap, uint32 ovflbitnum)
|
||||||
/* loop */ ;
|
/* loop */ ;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert to absolute page number by adding the number of bucket
|
* Convert to absolute page number by adding the number of bucket pages
|
||||||
* pages that exist before this split point.
|
* that exist before this split point.
|
||||||
*/
|
*/
|
||||||
return (BlockNumber) ((1 << i) + ovflbitnum);
|
return (BlockNumber) ((1 << i) + ovflbitnum);
|
||||||
}
|
}
|
||||||
|
@ -252,10 +252,10 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
|
||||||
/*
|
/*
|
||||||
* We create the new bitmap page with all pages marked "in use".
|
* We create the new bitmap page with all pages marked "in use".
|
||||||
* Actually two pages in the new bitmap's range will exist
|
* Actually two pages in the new bitmap's range will exist
|
||||||
* immediately: the bitmap page itself, and the following page
|
* immediately: the bitmap page itself, and the following page which
|
||||||
* which is the one we return to the caller. Both of these are
|
* is the one we return to the caller. Both of these are correctly
|
||||||
* correctly marked "in use". Subsequent pages do not exist yet,
|
* marked "in use". Subsequent pages do not exist yet, but it is
|
||||||
* but it is convenient to pre-mark them as "in use" too.
|
* convenient to pre-mark them as "in use" too.
|
||||||
*/
|
*/
|
||||||
_hash_initbitmap(rel, metap, bitno_to_blkno(metap, bit));
|
_hash_initbitmap(rel, metap, bitno_to_blkno(metap, bit));
|
||||||
|
|
||||||
|
@ -265,8 +265,8 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Nothing to do here; since the page was past the last used page,
|
* Nothing to do here; since the page was past the last used page, we
|
||||||
* we know its bitmap bit was preinitialized to "in use".
|
* know its bitmap bit was preinitialized to "in use".
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,8 +275,7 @@ _hash_getovflpage(Relation rel, Buffer metabuf)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust hashm_firstfree to avoid redundant searches. But don't risk
|
* Adjust hashm_firstfree to avoid redundant searches. But don't risk
|
||||||
* changing it if someone moved it while we were searching bitmap
|
* changing it if someone moved it while we were searching bitmap pages.
|
||||||
* pages.
|
|
||||||
*/
|
*/
|
||||||
if (metap->hashm_firstfree == orig_firstfree)
|
if (metap->hashm_firstfree == orig_firstfree)
|
||||||
metap->hashm_firstfree = bit + 1;
|
metap->hashm_firstfree = bit + 1;
|
||||||
|
@ -305,8 +304,7 @@ found:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Adjust hashm_firstfree to avoid redundant searches. But don't risk
|
* Adjust hashm_firstfree to avoid redundant searches. But don't risk
|
||||||
* changing it if someone moved it while we were searching bitmap
|
* changing it if someone moved it while we were searching bitmap pages.
|
||||||
* pages.
|
|
||||||
*/
|
*/
|
||||||
if (metap->hashm_firstfree == orig_firstfree)
|
if (metap->hashm_firstfree == orig_firstfree)
|
||||||
{
|
{
|
||||||
|
@ -394,10 +392,10 @@ _hash_freeovflpage(Relation rel, Buffer ovflbuf)
|
||||||
_hash_wrtbuf(rel, ovflbuf);
|
_hash_wrtbuf(rel, ovflbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Fix up the bucket chain. this is a doubly-linked list, so we must
|
* Fix up the bucket chain. this is a doubly-linked list, so we must fix
|
||||||
* fix up the bucket chain members behind and ahead of the overflow
|
* up the bucket chain members behind and ahead of the overflow page being
|
||||||
* page being deleted. No concurrency issues since we hold exclusive
|
* deleted. No concurrency issues since we hold exclusive lock on the
|
||||||
* lock on the entire bucket.
|
* entire bucket.
|
||||||
*/
|
*/
|
||||||
if (BlockNumberIsValid(prevblkno))
|
if (BlockNumberIsValid(prevblkno))
|
||||||
{
|
{
|
||||||
|
@ -488,12 +486,11 @@ _hash_initbitmap(Relation rel, HashMetaPage metap, BlockNumber blkno)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It is okay to write-lock the new bitmap page while holding metapage
|
* It is okay to write-lock the new bitmap page while holding metapage
|
||||||
* write lock, because no one else could be contending for the new
|
* write lock, because no one else could be contending for the new page.
|
||||||
* page.
|
|
||||||
*
|
*
|
||||||
* There is some loss of concurrency in possibly doing I/O for the new
|
* There is some loss of concurrency in possibly doing I/O for the new page
|
||||||
* page while holding the metapage lock, but this path is taken so
|
* while holding the metapage lock, but this path is taken so seldom that
|
||||||
* seldom that it's not worth worrying about.
|
* it's not worth worrying about.
|
||||||
*/
|
*/
|
||||||
buf = _hash_getbuf(rel, blkno, HASH_WRITE);
|
buf = _hash_getbuf(rel, blkno, HASH_WRITE);
|
||||||
pg = BufferGetPage(buf);
|
pg = BufferGetPage(buf);
|
||||||
|
@ -586,8 +583,8 @@ _hash_squeezebucket(Relation rel,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* find the last page in the bucket chain by starting at the base
|
* find the last page in the bucket chain by starting at the base bucket
|
||||||
* bucket page and working forward.
|
* page and working forward.
|
||||||
*/
|
*/
|
||||||
ropaque = wopaque;
|
ropaque = wopaque;
|
||||||
do
|
do
|
||||||
|
@ -655,22 +652,21 @@ _hash_squeezebucket(Relation rel,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* delete the tuple from the "read" page. PageIndexTupleDelete
|
* delete the tuple from the "read" page. PageIndexTupleDelete
|
||||||
* repacks the ItemId array, so 'roffnum' will be "advanced"
|
* repacks the ItemId array, so 'roffnum' will be "advanced" to
|
||||||
* to the "next" ItemId.
|
* the "next" ItemId.
|
||||||
*/
|
*/
|
||||||
PageIndexTupleDelete(rpage, roffnum);
|
PageIndexTupleDelete(rpage, roffnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if the "read" page is now empty because of the deletion (or
|
* if the "read" page is now empty because of the deletion (or because
|
||||||
* because it was empty when we got to it), free it.
|
* it was empty when we got to it), free it.
|
||||||
*
|
*
|
||||||
* Tricky point here: if our read and write pages are adjacent in the
|
* Tricky point here: if our read and write pages are adjacent in the
|
||||||
* bucket chain, our write lock on wbuf will conflict with
|
* bucket chain, our write lock on wbuf will conflict with
|
||||||
* _hash_freeovflpage's attempt to update the sibling links of the
|
* _hash_freeovflpage's attempt to update the sibling links of the
|
||||||
* removed page. However, in that case we are done anyway, so we
|
* removed page. However, in that case we are done anyway, so we can
|
||||||
* can simply drop the write lock before calling
|
* simply drop the write lock before calling _hash_freeovflpage.
|
||||||
* _hash_freeovflpage.
|
|
||||||
*/
|
*/
|
||||||
if (PageIsEmpty(rpage))
|
if (PageIsEmpty(rpage))
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.51 2005/06/09 21:01:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashpage.c,v 1.52 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Postgres hash pages look like ordinary relation pages. The opaque
|
* Postgres hash pages look like ordinary relation pages. The opaque
|
||||||
|
@ -240,10 +240,10 @@ _hash_metapinit(Relation rel)
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Determine the target fill factor (tuples per bucket) for this
|
* Determine the target fill factor (tuples per bucket) for this index.
|
||||||
* index. The idea is to make the fill factor correspond to pages
|
* The idea is to make the fill factor correspond to pages about 3/4ths
|
||||||
* about 3/4ths full. We can compute it exactly if the index datatype
|
* full. We can compute it exactly if the index datatype is fixed-width,
|
||||||
* is fixed-width, but for var-width there's some guessing involved.
|
* but for var-width there's some guessing involved.
|
||||||
*/
|
*/
|
||||||
data_width = get_typavgwidth(RelationGetDescr(rel)->attrs[0]->atttypid,
|
data_width = get_typavgwidth(RelationGetDescr(rel)->attrs[0]->atttypid,
|
||||||
RelationGetDescr(rel)->attrs[0]->atttypmod);
|
RelationGetDescr(rel)->attrs[0]->atttypmod);
|
||||||
|
@ -289,9 +289,8 @@ _hash_metapinit(Relation rel)
|
||||||
metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
|
metap->hashm_procid = index_getprocid(rel, 1, HASHPROC);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We initialize the index with two buckets, 0 and 1, occupying
|
* We initialize the index with two buckets, 0 and 1, occupying physical
|
||||||
* physical blocks 1 and 2. The first freespace bitmap page is in
|
* blocks 1 and 2. The first freespace bitmap page is in block 3.
|
||||||
* block 3.
|
|
||||||
*/
|
*/
|
||||||
metap->hashm_maxbucket = metap->hashm_lowmask = 1; /* nbuckets - 1 */
|
metap->hashm_maxbucket = metap->hashm_lowmask = 1; /* nbuckets - 1 */
|
||||||
metap->hashm_highmask = 3; /* (nbuckets << 1) - 1 */
|
metap->hashm_highmask = 3; /* (nbuckets << 1) - 1 */
|
||||||
|
@ -321,8 +320,8 @@ _hash_metapinit(Relation rel)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize first bitmap page. Can't do this until we create the
|
* Initialize first bitmap page. Can't do this until we create the first
|
||||||
* first two buckets, else smgr will complain.
|
* two buckets, else smgr will complain.
|
||||||
*/
|
*/
|
||||||
_hash_initbitmap(rel, metap, 3);
|
_hash_initbitmap(rel, metap, 3);
|
||||||
|
|
||||||
|
@ -367,15 +366,14 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||||
* Obtain the page-zero lock to assert the right to begin a split (see
|
* Obtain the page-zero lock to assert the right to begin a split (see
|
||||||
* README).
|
* README).
|
||||||
*
|
*
|
||||||
* Note: deadlock should be impossible here. Our own backend could only
|
* Note: deadlock should be impossible here. Our own backend could only be
|
||||||
* be holding bucket sharelocks due to stopped indexscans; those will
|
* holding bucket sharelocks due to stopped indexscans; those will not
|
||||||
* not block other holders of the page-zero lock, who are only
|
* block other holders of the page-zero lock, who are only interested in
|
||||||
* interested in acquiring bucket sharelocks themselves. Exclusive
|
* acquiring bucket sharelocks themselves. Exclusive bucket locks are
|
||||||
* bucket locks are only taken here and in hashbulkdelete, and neither
|
* only taken here and in hashbulkdelete, and neither of these operations
|
||||||
* of these operations needs any additional locks to complete. (If,
|
* needs any additional locks to complete. (If, due to some flaw in this
|
||||||
* due to some flaw in this reasoning, we manage to deadlock anyway,
|
* reasoning, we manage to deadlock anyway, it's okay to error out; the
|
||||||
* it's okay to error out; the index will be left in a consistent
|
* index will be left in a consistent state.)
|
||||||
* state.)
|
|
||||||
*/
|
*/
|
||||||
_hash_getlock(rel, 0, HASH_EXCLUSIVE);
|
_hash_getlock(rel, 0, HASH_EXCLUSIVE);
|
||||||
|
|
||||||
|
@ -386,8 +384,8 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||||
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
|
_hash_checkpage(rel, (Page) metap, LH_META_PAGE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check to see if split is still needed; someone else might have
|
* Check to see if split is still needed; someone else might have already
|
||||||
* already done one while we waited for the lock.
|
* done one while we waited for the lock.
|
||||||
*
|
*
|
||||||
* Make sure this stays in sync with _hash_doinsert()
|
* Make sure this stays in sync with _hash_doinsert()
|
||||||
*/
|
*/
|
||||||
|
@ -402,11 +400,11 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||||
* The lock protects us against other backends, but not against our own
|
* The lock protects us against other backends, but not against our own
|
||||||
* backend. Must check for active scans separately.
|
* backend. Must check for active scans separately.
|
||||||
*
|
*
|
||||||
* Ideally we would lock the new bucket too before proceeding, but if we
|
* Ideally we would lock the new bucket too before proceeding, but if we are
|
||||||
* are about to cross a splitpoint then the BUCKET_TO_BLKNO mapping
|
* about to cross a splitpoint then the BUCKET_TO_BLKNO mapping isn't
|
||||||
* isn't correct yet. For simplicity we update the metapage first and
|
* correct yet. For simplicity we update the metapage first and then
|
||||||
* then lock. This should be okay because no one else should be
|
* lock. This should be okay because no one else should be trying to lock
|
||||||
* trying to lock the new bucket yet...
|
* the new bucket yet...
|
||||||
*/
|
*/
|
||||||
new_bucket = metap->hashm_maxbucket + 1;
|
new_bucket = metap->hashm_maxbucket + 1;
|
||||||
old_bucket = (new_bucket & metap->hashm_lowmask);
|
old_bucket = (new_bucket & metap->hashm_lowmask);
|
||||||
|
@ -420,14 +418,13 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay to proceed with split. Update the metapage bucket mapping
|
* Okay to proceed with split. Update the metapage bucket mapping info.
|
||||||
* info.
|
|
||||||
*
|
*
|
||||||
* Since we are scribbling on the metapage data right in the shared
|
* Since we are scribbling on the metapage data right in the shared buffer,
|
||||||
* buffer, any failure in this next little bit leaves us with a big
|
* any failure in this next little bit leaves us with a big problem: the
|
||||||
* problem: the metapage is effectively corrupt but could get written
|
* metapage is effectively corrupt but could get written back to disk. We
|
||||||
* back to disk. We don't really expect any failure, but just to be
|
* don't really expect any failure, but just to be sure, establish a
|
||||||
* sure, establish a critical section.
|
* critical section.
|
||||||
*/
|
*/
|
||||||
START_CRIT_SECTION();
|
START_CRIT_SECTION();
|
||||||
|
|
||||||
|
@ -443,8 +440,8 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||||
/*
|
/*
|
||||||
* If the split point is increasing (hashm_maxbucket's log base 2
|
* If the split point is increasing (hashm_maxbucket's log base 2
|
||||||
* increases), we need to adjust the hashm_spares[] array and
|
* increases), we need to adjust the hashm_spares[] array and
|
||||||
* hashm_ovflpoint so that future overflow pages will be created
|
* hashm_ovflpoint so that future overflow pages will be created beyond
|
||||||
* beyond this new batch of bucket pages.
|
* this new batch of bucket pages.
|
||||||
*
|
*
|
||||||
* XXX should initialize new bucket pages to prevent out-of-order page
|
* XXX should initialize new bucket pages to prevent out-of-order page
|
||||||
* creation? Don't wanna do it right here though.
|
* creation? Don't wanna do it right here though.
|
||||||
|
@ -471,10 +468,9 @@ _hash_expandtable(Relation rel, Buffer metabuf)
|
||||||
/*
|
/*
|
||||||
* Copy bucket mapping info now; this saves re-accessing the meta page
|
* Copy bucket mapping info now; this saves re-accessing the meta page
|
||||||
* inside _hash_splitbucket's inner loop. Note that once we drop the
|
* inside _hash_splitbucket's inner loop. Note that once we drop the
|
||||||
* split lock, other splits could begin, so these values might be out
|
* split lock, other splits could begin, so these values might be out of
|
||||||
* of date before _hash_splitbucket finishes. That's okay, since all
|
* date before _hash_splitbucket finishes. That's okay, since all it
|
||||||
* it needs is to tell which of these two buckets to map hashkeys
|
* needs is to tell which of these two buckets to map hashkeys into.
|
||||||
* into.
|
|
||||||
*/
|
*/
|
||||||
maxbucket = metap->hashm_maxbucket;
|
maxbucket = metap->hashm_maxbucket;
|
||||||
highmask = metap->hashm_highmask;
|
highmask = metap->hashm_highmask;
|
||||||
|
@ -554,9 +550,9 @@ _hash_splitbucket(Relation rel,
|
||||||
TupleDesc itupdesc = RelationGetDescr(rel);
|
TupleDesc itupdesc = RelationGetDescr(rel);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It should be okay to simultaneously write-lock pages from each
|
* It should be okay to simultaneously write-lock pages from each bucket,
|
||||||
* bucket, since no one else can be trying to acquire buffer lock on
|
* since no one else can be trying to acquire buffer lock on pages of
|
||||||
* pages of either bucket.
|
* either bucket.
|
||||||
*/
|
*/
|
||||||
oblkno = start_oblkno;
|
oblkno = start_oblkno;
|
||||||
nblkno = start_nblkno;
|
nblkno = start_nblkno;
|
||||||
|
@ -578,17 +574,17 @@ _hash_splitbucket(Relation rel,
|
||||||
nopaque->hasho_filler = HASHO_FILL;
|
nopaque->hasho_filler = HASHO_FILL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Partition the tuples in the old bucket between the old bucket and
|
* Partition the tuples in the old bucket between the old bucket and the
|
||||||
* the new bucket, advancing along the old bucket's overflow bucket
|
* new bucket, advancing along the old bucket's overflow bucket chain and
|
||||||
* chain and adding overflow pages to the new bucket as needed.
|
* adding overflow pages to the new bucket as needed.
|
||||||
*/
|
*/
|
||||||
ooffnum = FirstOffsetNumber;
|
ooffnum = FirstOffsetNumber;
|
||||||
omaxoffnum = PageGetMaxOffsetNumber(opage);
|
omaxoffnum = PageGetMaxOffsetNumber(opage);
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* at each iteration through this loop, each of these variables
|
* at each iteration through this loop, each of these variables should
|
||||||
* should be up-to-date: obuf opage oopaque ooffnum omaxoffnum
|
* be up-to-date: obuf opage oopaque ooffnum omaxoffnum
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* check if we're at the end of the page */
|
/* check if we're at the end of the page */
|
||||||
|
@ -600,8 +596,8 @@ _hash_splitbucket(Relation rel,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we ran out of tuples on this particular page, but we have
|
* we ran out of tuples on this particular page, but we have more
|
||||||
* more overflow pages; advance to next page.
|
* overflow pages; advance to next page.
|
||||||
*/
|
*/
|
||||||
_hash_wrtbuf(rel, obuf);
|
_hash_wrtbuf(rel, obuf);
|
||||||
|
|
||||||
|
@ -618,8 +614,7 @@ _hash_splitbucket(Relation rel,
|
||||||
* Re-hash the tuple to determine which bucket it now belongs in.
|
* Re-hash the tuple to determine which bucket it now belongs in.
|
||||||
*
|
*
|
||||||
* It is annoying to call the hash function while holding locks, but
|
* It is annoying to call the hash function while holding locks, but
|
||||||
* releasing and relocking the page for each tuple is unappealing
|
* releasing and relocking the page for each tuple is unappealing too.
|
||||||
* too.
|
|
||||||
*/
|
*/
|
||||||
hitem = (HashItem) PageGetItem(opage, PageGetItemId(opage, ooffnum));
|
hitem = (HashItem) PageGetItem(opage, PageGetItemId(opage, ooffnum));
|
||||||
itup = &(hitem->hash_itup);
|
itup = &(hitem->hash_itup);
|
||||||
|
@ -632,9 +627,9 @@ _hash_splitbucket(Relation rel,
|
||||||
if (bucket == nbucket)
|
if (bucket == nbucket)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* insert the tuple into the new bucket. if it doesn't fit on
|
* insert the tuple into the new bucket. if it doesn't fit on the
|
||||||
* the current page in the new bucket, we must allocate a new
|
* current page in the new bucket, we must allocate a new overflow
|
||||||
* overflow page and place the tuple on that page instead.
|
* page and place the tuple on that page instead.
|
||||||
*/
|
*/
|
||||||
itemsz = IndexTupleDSize(hitem->hash_itup)
|
itemsz = IndexTupleDSize(hitem->hash_itup)
|
||||||
+ (sizeof(HashItemData) - sizeof(IndexTupleData));
|
+ (sizeof(HashItemData) - sizeof(IndexTupleData));
|
||||||
|
@ -659,13 +654,13 @@ _hash_splitbucket(Relation rel,
|
||||||
RelationGetRelationName(rel));
|
RelationGetRelationName(rel));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* now delete the tuple from the old bucket. after this
|
* now delete the tuple from the old bucket. after this section
|
||||||
* section of code, 'ooffnum' will actually point to the
|
* of code, 'ooffnum' will actually point to the ItemId to which
|
||||||
* ItemId to which we would point if we had advanced it before
|
* we would point if we had advanced it before the deletion
|
||||||
* the deletion (PageIndexTupleDelete repacks the ItemId
|
* (PageIndexTupleDelete repacks the ItemId array). this also
|
||||||
* array). this also means that 'omaxoffnum' is exactly one
|
* means that 'omaxoffnum' is exactly one less than it used to be,
|
||||||
* less than it used to be, so we really can just decrement it
|
* so we really can just decrement it instead of calling
|
||||||
* instead of calling PageGetMaxOffsetNumber.
|
* PageGetMaxOffsetNumber.
|
||||||
*/
|
*/
|
||||||
PageIndexTupleDelete(opage, ooffnum);
|
PageIndexTupleDelete(opage, ooffnum);
|
||||||
omaxoffnum = OffsetNumberPrev(omaxoffnum);
|
omaxoffnum = OffsetNumberPrev(omaxoffnum);
|
||||||
|
@ -673,9 +668,9 @@ _hash_splitbucket(Relation rel,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* the tuple stays on this page. we didn't move anything, so
|
* the tuple stays on this page. we didn't move anything, so we
|
||||||
* we didn't delete anything and therefore we don't have to
|
* didn't delete anything and therefore we don't have to change
|
||||||
* change 'omaxoffnum'.
|
* 'omaxoffnum'.
|
||||||
*/
|
*/
|
||||||
Assert(bucket == obucket);
|
Assert(bucket == obucket);
|
||||||
ooffnum = OffsetNumberNext(ooffnum);
|
ooffnum = OffsetNumberNext(ooffnum);
|
||||||
|
@ -683,11 +678,10 @@ _hash_splitbucket(Relation rel,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We're at the end of the old bucket chain, so we're done
|
* We're at the end of the old bucket chain, so we're done partitioning
|
||||||
* partitioning the tuples. Before quitting, call _hash_squeezebucket
|
* the tuples. Before quitting, call _hash_squeezebucket to ensure the
|
||||||
* to ensure the tuples remaining in the old bucket (including the
|
* tuples remaining in the old bucket (including the overflow pages) are
|
||||||
* overflow pages) are packed as tightly as possible. The new bucket
|
* packed as tightly as possible. The new bucket is already tight.
|
||||||
* is already tight.
|
|
||||||
*/
|
*/
|
||||||
_hash_wrtbuf(rel, obuf);
|
_hash_wrtbuf(rel, obuf);
|
||||||
_hash_wrtbuf(rel, nbuf);
|
_hash_wrtbuf(rel, nbuf);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.38 2004/12/31 21:59:13 pgsql Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashscan.c,v 1.39 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -44,9 +44,9 @@ ReleaseResources_hash(void)
|
||||||
HashScanList next;
|
HashScanList next;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: this should be a no-op during normal query shutdown. However,
|
* Note: this should be a no-op during normal query shutdown. However, in
|
||||||
* in an abort situation ExecutorEnd is not called and so there may be
|
* an abort situation ExecutorEnd is not called and so there may be open
|
||||||
* open index scans to clean up.
|
* index scans to clean up.
|
||||||
*/
|
*/
|
||||||
prev = NULL;
|
prev = NULL;
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.39 2005/10/06 02:29:08 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/hash/hashsearch.c,v 1.40 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -137,11 +137,10 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
ItemPointerSetInvalid(current);
|
ItemPointerSetInvalid(current);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not support hash scans with no index qualification, because
|
* We do not support hash scans with no index qualification, because we
|
||||||
* we would have to read the whole index rather than just one bucket.
|
* would have to read the whole index rather than just one bucket. That
|
||||||
* That creates a whole raft of problems, since we haven't got a
|
* creates a whole raft of problems, since we haven't got a practical way
|
||||||
* practical way to lock all the buckets against splits or
|
* to lock all the buckets against splits or compactions.
|
||||||
* compactions.
|
|
||||||
*/
|
*/
|
||||||
if (scan->numberOfKeys < 1)
|
if (scan->numberOfKeys < 1)
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -149,21 +148,21 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
errmsg("hash indexes do not support whole-index scans")));
|
errmsg("hash indexes do not support whole-index scans")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the constant in the index qual is NULL, assume it cannot match
|
* If the constant in the index qual is NULL, assume it cannot match any
|
||||||
* any items in the index.
|
* items in the index.
|
||||||
*/
|
*/
|
||||||
if (scan->keyData[0].sk_flags & SK_ISNULL)
|
if (scan->keyData[0].sk_flags & SK_ISNULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay to compute the hash key. We want to do this before acquiring
|
* Okay to compute the hash key. We want to do this before acquiring any
|
||||||
* any locks, in case a user-defined hash function happens to be slow.
|
* locks, in case a user-defined hash function happens to be slow.
|
||||||
*/
|
*/
|
||||||
hashkey = _hash_datum2hashkey(rel, scan->keyData[0].sk_argument);
|
hashkey = _hash_datum2hashkey(rel, scan->keyData[0].sk_argument);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire shared split lock so we can compute the target bucket
|
* Acquire shared split lock so we can compute the target bucket safely
|
||||||
* safely (see README).
|
* (see README).
|
||||||
*/
|
*/
|
||||||
_hash_getlock(rel, 0, HASH_SHARE);
|
_hash_getlock(rel, 0, HASH_SHARE);
|
||||||
|
|
||||||
|
@ -186,8 +185,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
_hash_relbuf(rel, metabuf);
|
_hash_relbuf(rel, metabuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire share lock on target bucket; then we can release split
|
* Acquire share lock on target bucket; then we can release split lock.
|
||||||
* lock.
|
|
||||||
*/
|
*/
|
||||||
_hash_getlock(rel, blkno, HASH_SHARE);
|
_hash_getlock(rel, blkno, HASH_SHARE);
|
||||||
|
|
||||||
|
@ -263,9 +261,9 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||||
bucket = opaque->hasho_bucket;
|
bucket = opaque->hasho_bucket;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If _hash_step is called from _hash_first, current will not be
|
* If _hash_step is called from _hash_first, current will not be valid, so
|
||||||
* valid, so we can't dereference it. However, in that case, we
|
* we can't dereference it. However, in that case, we presumably want to
|
||||||
* presumably want to start at the beginning/end of the page...
|
* start at the beginning/end of the page...
|
||||||
*/
|
*/
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
if (ItemPointerIsValid(current))
|
if (ItemPointerIsValid(current))
|
||||||
|
@ -276,8 +274,8 @@ _hash_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||||
/*
|
/*
|
||||||
* 'offnum' now points to the last tuple we have seen (if any).
|
* 'offnum' now points to the last tuple we have seen (if any).
|
||||||
*
|
*
|
||||||
* continue to step through tuples until: 1) we get to the end of the
|
* continue to step through tuples until: 1) we get to the end of the bucket
|
||||||
* bucket chain or 2) we find a valid tuple.
|
* chain or 2) we find a valid tuple.
|
||||||
*/
|
*/
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.199 2005/10/06 02:29:10 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.200 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -272,8 +272,8 @@ heapgettup(Relation relation,
|
||||||
/* 'dir' is now non-zero */
|
/* 'dir' is now non-zero */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* calculate line pointer and number of remaining items to check on
|
* calculate line pointer and number of remaining items to check on this
|
||||||
* this page.
|
* page.
|
||||||
*/
|
*/
|
||||||
lpp = PageGetItemId(dp, lineoff);
|
lpp = PageGetItemId(dp, lineoff);
|
||||||
if (dir < 0)
|
if (dir < 0)
|
||||||
|
@ -282,8 +282,8 @@ heapgettup(Relation relation,
|
||||||
linesleft = lines - lineoff;
|
linesleft = lines - lineoff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* advance the scan until we find a qualifying tuple or run out of
|
* advance the scan until we find a qualifying tuple or run out of stuff
|
||||||
* stuff to scan
|
* to scan
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -321,15 +321,14 @@ heapgettup(Relation relation,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
++lpp; /* move forward in this page's ItemId
|
++lpp; /* move forward in this page's ItemId array */
|
||||||
* array */
|
|
||||||
++lineoff;
|
++lineoff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we get here, it means we've exhausted the items on this page
|
* if we get here, it means we've exhausted the items on this page and
|
||||||
* and it's time to move to the next.
|
* it's time to move to the next.
|
||||||
*/
|
*/
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(*buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
|
@ -506,15 +505,15 @@ relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for shared-cache-inval messages before trying to open the
|
* Check for shared-cache-inval messages before trying to open the
|
||||||
* relation. This is needed to cover the case where the name
|
* relation. This is needed to cover the case where the name identifies a
|
||||||
* identifies a rel that has been dropped and recreated since the
|
* rel that has been dropped and recreated since the start of our
|
||||||
* start of our transaction: if we don't flush the old syscache entry
|
* transaction: if we don't flush the old syscache entry then we'll latch
|
||||||
* then we'll latch onto that entry and suffer an error when we do
|
* onto that entry and suffer an error when we do LockRelation. Note that
|
||||||
* LockRelation. Note that relation_open does not need to do this,
|
* relation_open does not need to do this, since a relation's OID never
|
||||||
* since a relation's OID never changes.
|
* changes.
|
||||||
*
|
*
|
||||||
* We skip this if asked for NoLock, on the assumption that the caller
|
* We skip this if asked for NoLock, on the assumption that the caller has
|
||||||
* has already ensured some appropriate lock is held.
|
* already ensured some appropriate lock is held.
|
||||||
*/
|
*/
|
||||||
if (lockmode != NoLock)
|
if (lockmode != NoLock)
|
||||||
AcceptInvalidationMessages();
|
AcceptInvalidationMessages();
|
||||||
|
@ -633,9 +632,9 @@ heap_beginscan(Relation relation, Snapshot snapshot,
|
||||||
/*
|
/*
|
||||||
* increment relation ref count while scanning relation
|
* increment relation ref count while scanning relation
|
||||||
*
|
*
|
||||||
* This is just to make really sure the relcache entry won't go away
|
* This is just to make really sure the relcache entry won't go away while
|
||||||
* while the scan has a pointer to it. Caller should be holding the
|
* the scan has a pointer to it. Caller should be holding the rel open
|
||||||
* rel open anyway, so this is redundant in all normal scenarios...
|
* anyway, so this is redundant in all normal scenarios...
|
||||||
*/
|
*/
|
||||||
RelationIncrementReferenceCount(relation);
|
RelationIncrementReferenceCount(relation);
|
||||||
|
|
||||||
|
@ -649,8 +648,8 @@ heap_beginscan(Relation relation, Snapshot snapshot,
|
||||||
scan->rs_nkeys = nkeys;
|
scan->rs_nkeys = nkeys;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* we do this here instead of in initscan() because heap_rescan also
|
* we do this here instead of in initscan() because heap_rescan also calls
|
||||||
* calls initscan() and we don't want to allocate memory again
|
* initscan() and we don't want to allocate memory again
|
||||||
*/
|
*/
|
||||||
if (nkeys > 0)
|
if (nkeys > 0)
|
||||||
scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
|
scan->rs_key = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
|
||||||
|
@ -763,8 +762,8 @@ heap_getnext(HeapScanDesc scan, ScanDirection direction)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we get here it means we have a new current scan tuple, so point
|
* if we get here it means we have a new current scan tuple, so point to
|
||||||
* to the proper return buffer and return the tuple.
|
* the proper return buffer and return the tuple.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
HEAPDEBUG_3; /* heap_getnext returning tuple */
|
HEAPDEBUG_3; /* heap_getnext returning tuple */
|
||||||
|
@ -859,8 +858,8 @@ heap_release_fetch(Relation relation,
|
||||||
dp = (PageHeader) BufferGetPage(buffer);
|
dp = (PageHeader) BufferGetPage(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We'd better check for out-of-range offnum in case of VACUUM since
|
* We'd better check for out-of-range offnum in case of VACUUM since the
|
||||||
* the TID was obtained.
|
* TID was obtained.
|
||||||
*/
|
*/
|
||||||
offnum = ItemPointerGetOffsetNumber(tid);
|
offnum = ItemPointerGetOffsetNumber(tid);
|
||||||
if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
|
if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
|
||||||
|
@ -969,10 +968,10 @@ heap_get_latest_tid(Relation relation,
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since this can be called with user-supplied TID, don't trust the
|
* Since this can be called with user-supplied TID, don't trust the input
|
||||||
* input too much. (RelationGetNumberOfBlocks is an expensive check,
|
* too much. (RelationGetNumberOfBlocks is an expensive check, so we
|
||||||
* so we don't check t_ctid links again this way. Note that it would
|
* don't check t_ctid links again this way. Note that it would not do to
|
||||||
* not do to call it just once and save the result, either.)
|
* call it just once and save the result, either.)
|
||||||
*/
|
*/
|
||||||
blk = ItemPointerGetBlockNumber(tid);
|
blk = ItemPointerGetBlockNumber(tid);
|
||||||
if (blk >= RelationGetNumberOfBlocks(relation))
|
if (blk >= RelationGetNumberOfBlocks(relation))
|
||||||
|
@ -980,9 +979,9 @@ heap_get_latest_tid(Relation relation,
|
||||||
blk, RelationGetRelationName(relation));
|
blk, RelationGetRelationName(relation));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop to chase down t_ctid links. At top of loop, ctid is the
|
* Loop to chase down t_ctid links. At top of loop, ctid is the tuple we
|
||||||
* tuple we need to examine, and *tid is the TID we will return if
|
* need to examine, and *tid is the TID we will return if ctid turns out
|
||||||
* ctid turns out to be bogus.
|
* to be bogus.
|
||||||
*
|
*
|
||||||
* Note that we will loop until we reach the end of the t_ctid chain.
|
* Note that we will loop until we reach the end of the t_ctid chain.
|
||||||
* Depending on the snapshot passed, there might be at most one visible
|
* Depending on the snapshot passed, there might be at most one visible
|
||||||
|
@ -1008,8 +1007,8 @@ heap_get_latest_tid(Relation relation,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for bogus item number. This is not treated as an error
|
* Check for bogus item number. This is not treated as an error
|
||||||
* condition because it can happen while following a t_ctid link.
|
* condition because it can happen while following a t_ctid link. We
|
||||||
* We just assume that the prior tid is OK and return it unchanged.
|
* just assume that the prior tid is OK and return it unchanged.
|
||||||
*/
|
*/
|
||||||
offnum = ItemPointerGetOffsetNumber(&ctid);
|
offnum = ItemPointerGetOffsetNumber(&ctid);
|
||||||
if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
|
if (offnum < FirstOffsetNumber || offnum > PageGetMaxOffsetNumber(dp))
|
||||||
|
@ -1102,13 +1101,12 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the object id of this tuple has already been assigned, trust
|
* If the object id of this tuple has already been assigned, trust the
|
||||||
* the caller. There are a couple of ways this can happen. At
|
* caller. There are a couple of ways this can happen. At initial db
|
||||||
* initial db creation, the backend program sets oids for tuples.
|
* creation, the backend program sets oids for tuples. When we define
|
||||||
* When we define an index, we set the oid. Finally, in the
|
* an index, we set the oid. Finally, in the future, we may allow
|
||||||
* future, we may allow users to set their own object ids in order
|
* users to set their own object ids in order to support a persistent
|
||||||
* to support a persistent object store (objects need to contain
|
* object store (objects need to contain pointers to one another).
|
||||||
* pointers to one another).
|
|
||||||
*/
|
*/
|
||||||
if (!OidIsValid(HeapTupleGetOid(tup)))
|
if (!OidIsValid(HeapTupleGetOid(tup)))
|
||||||
HeapTupleSetOid(tup, GetNewOid(relation));
|
HeapTupleSetOid(tup, GetNewOid(relation));
|
||||||
|
@ -1129,8 +1127,7 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the new tuple is too big for storage or contains already toasted
|
* If the new tuple is too big for storage or contains already toasted
|
||||||
* out-of-line attributes from some other relation, invoke the
|
* out-of-line attributes from some other relation, invoke the toaster.
|
||||||
* toaster.
|
|
||||||
*/
|
*/
|
||||||
if (HeapTupleHasExternal(tup) ||
|
if (HeapTupleHasExternal(tup) ||
|
||||||
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
|
(MAXALIGN(tup->t_len) > TOAST_TUPLE_THRESHOLD))
|
||||||
|
@ -1172,9 +1169,9 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||||
xlhdr.t_hoff = tup->t_data->t_hoff;
|
xlhdr.t_hoff = tup->t_data->t_hoff;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* note we mark rdata[1] as belonging to buffer; if XLogInsert
|
* note we mark rdata[1] as belonging to buffer; if XLogInsert decides
|
||||||
* decides to write the whole page to the xlog, we don't need to
|
* to write the whole page to the xlog, we don't need to store
|
||||||
* store xl_heap_header in the xlog.
|
* xl_heap_header in the xlog.
|
||||||
*/
|
*/
|
||||||
rdata[1].data = (char *) &xlhdr;
|
rdata[1].data = (char *) &xlhdr;
|
||||||
rdata[1].len = SizeOfHeapHeader;
|
rdata[1].len = SizeOfHeapHeader;
|
||||||
|
@ -1190,9 +1187,9 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||||
rdata[2].next = NULL;
|
rdata[2].next = NULL;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the single and first tuple on page, we can reinit
|
* If this is the single and first tuple on page, we can reinit the
|
||||||
* the page instead of restoring the whole thing. Set flag, and
|
* page instead of restoring the whole thing. Set flag, and hide
|
||||||
* hide buffer references from XLogInsert.
|
* buffer references from XLogInsert.
|
||||||
*/
|
*/
|
||||||
if (ItemPointerGetOffsetNumber(&(tup->t_self)) == FirstOffsetNumber &&
|
if (ItemPointerGetOffsetNumber(&(tup->t_self)) == FirstOffsetNumber &&
|
||||||
PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
|
PageGetMaxOffsetNumber(page) == FirstOffsetNumber)
|
||||||
|
@ -1213,10 +1210,10 @@ heap_insert(Relation relation, HeapTuple tup, CommandId cid,
|
||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If tuple is cachable, mark it for invalidation from the caches in
|
* If tuple is cachable, mark it for invalidation from the caches in case
|
||||||
* case we abort. Note it is OK to do this after WriteBuffer releases
|
* we abort. Note it is OK to do this after WriteBuffer releases the
|
||||||
* the buffer, because the "tup" data structure is all in local
|
* buffer, because the "tup" data structure is all in local memory, not in
|
||||||
* memory, not in the shared buffer.
|
* the shared buffer.
|
||||||
*/
|
*/
|
||||||
CacheInvalidateHeapTuple(relation, tup);
|
CacheInvalidateHeapTuple(relation, tup);
|
||||||
|
|
||||||
|
@ -1310,13 +1307,13 @@ l1:
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire tuple lock to establish our priority for the tuple
|
* Acquire tuple lock to establish our priority for the tuple (see
|
||||||
* (see heap_lock_tuple). LockTuple will release us when we are
|
* heap_lock_tuple). LockTuple will release us when we are
|
||||||
* next-in-line for the tuple.
|
* next-in-line for the tuple.
|
||||||
*
|
*
|
||||||
* If we are forced to "start over" below, we keep the tuple lock;
|
* If we are forced to "start over" below, we keep the tuple lock; this
|
||||||
* this arranges that we stay at the head of the line while
|
* arranges that we stay at the head of the line while rechecking
|
||||||
* rechecking tuple state.
|
* tuple state.
|
||||||
*/
|
*/
|
||||||
if (!have_tuple_lock)
|
if (!have_tuple_lock)
|
||||||
{
|
{
|
||||||
|
@ -1347,12 +1344,12 @@ l1:
|
||||||
goto l1;
|
goto l1;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* You might think the multixact is necessarily done here, but
|
* You might think the multixact is necessarily done here, but not
|
||||||
* not so: it could have surviving members, namely our own xact
|
* so: it could have surviving members, namely our own xact or
|
||||||
* or other subxacts of this backend. It is legal for us to
|
* other subxacts of this backend. It is legal for us to delete
|
||||||
* delete the tuple in either case, however (the latter case is
|
* the tuple in either case, however (the latter case is
|
||||||
* essentially a situation of upgrading our former shared lock
|
* essentially a situation of upgrading our former shared lock to
|
||||||
* to exclusive). We don't bother changing the on-disk hint bits
|
* exclusive). We don't bother changing the on-disk hint bits
|
||||||
* since we are about to overwrite the xmax altogether.
|
* since we are about to overwrite the xmax altogether.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@ -1385,8 +1382,8 @@ l1:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We may overwrite if previous xmax aborted, or if it committed
|
* We may overwrite if previous xmax aborted, or if it committed but
|
||||||
* but only locked the tuple without updating it.
|
* only locked the tuple without updating it.
|
||||||
*/
|
*/
|
||||||
if (tp.t_data->t_infomask & (HEAP_XMAX_INVALID |
|
if (tp.t_data->t_infomask & (HEAP_XMAX_INVALID |
|
||||||
HEAP_IS_LOCKED))
|
HEAP_IS_LOCKED))
|
||||||
|
@ -1467,18 +1464,18 @@ l1:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the tuple has toasted out-of-line attributes, we need to delete
|
* If the tuple has toasted out-of-line attributes, we need to delete
|
||||||
* those items too. We have to do this before WriteBuffer because we
|
* those items too. We have to do this before WriteBuffer because we need
|
||||||
* need to look at the contents of the tuple, but it's OK to release
|
* to look at the contents of the tuple, but it's OK to release the
|
||||||
* the context lock on the buffer first.
|
* context lock on the buffer first.
|
||||||
*/
|
*/
|
||||||
if (HeapTupleHasExternal(&tp))
|
if (HeapTupleHasExternal(&tp))
|
||||||
heap_tuple_toast_attrs(relation, NULL, &tp);
|
heap_tuple_toast_attrs(relation, NULL, &tp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark tuple for invalidation from system caches at next command
|
* Mark tuple for invalidation from system caches at next command
|
||||||
* boundary. We have to do this before WriteBuffer because we need to
|
* boundary. We have to do this before WriteBuffer because we need to look
|
||||||
* look at the contents of the tuple, so we need to hold our refcount
|
* at the contents of the tuple, so we need to hold our refcount on the
|
||||||
* on the buffer.
|
* buffer.
|
||||||
*/
|
*/
|
||||||
CacheInvalidateHeapTuple(relation, &tp);
|
CacheInvalidateHeapTuple(relation, &tp);
|
||||||
|
|
||||||
|
@ -1598,8 +1595,8 @@ heap_update(Relation relation, ItemPointer otid, HeapTuple newtup,
|
||||||
/*
|
/*
|
||||||
* Note: beyond this point, use oldtup not otid to refer to old tuple.
|
* Note: beyond this point, use oldtup not otid to refer to old tuple.
|
||||||
* otid may very well point at newtup->t_self, which we will overwrite
|
* otid may very well point at newtup->t_self, which we will overwrite
|
||||||
* with the new tuple's location, so there's great risk of confusion
|
* with the new tuple's location, so there's great risk of confusion if we
|
||||||
* if we use otid anymore.
|
* use otid anymore.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
l2:
|
l2:
|
||||||
|
@ -1623,13 +1620,13 @@ l2:
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire tuple lock to establish our priority for the tuple
|
* Acquire tuple lock to establish our priority for the tuple (see
|
||||||
* (see heap_lock_tuple). LockTuple will release us when we are
|
* heap_lock_tuple). LockTuple will release us when we are
|
||||||
* next-in-line for the tuple.
|
* next-in-line for the tuple.
|
||||||
*
|
*
|
||||||
* If we are forced to "start over" below, we keep the tuple lock;
|
* If we are forced to "start over" below, we keep the tuple lock; this
|
||||||
* this arranges that we stay at the head of the line while
|
* arranges that we stay at the head of the line while rechecking
|
||||||
* rechecking tuple state.
|
* tuple state.
|
||||||
*/
|
*/
|
||||||
if (!have_tuple_lock)
|
if (!have_tuple_lock)
|
||||||
{
|
{
|
||||||
|
@ -1660,12 +1657,12 @@ l2:
|
||||||
goto l2;
|
goto l2;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* You might think the multixact is necessarily done here, but
|
* You might think the multixact is necessarily done here, but not
|
||||||
* not so: it could have surviving members, namely our own xact
|
* so: it could have surviving members, namely our own xact or
|
||||||
* or other subxacts of this backend. It is legal for us to
|
* other subxacts of this backend. It is legal for us to update
|
||||||
* update the tuple in either case, however (the latter case is
|
* the tuple in either case, however (the latter case is
|
||||||
* essentially a situation of upgrading our former shared lock
|
* essentially a situation of upgrading our former shared lock to
|
||||||
* to exclusive). We don't bother changing the on-disk hint bits
|
* exclusive). We don't bother changing the on-disk hint bits
|
||||||
* since we are about to overwrite the xmax altogether.
|
* since we are about to overwrite the xmax altogether.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
@ -1698,8 +1695,8 @@ l2:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We may overwrite if previous xmax aborted, or if it committed
|
* We may overwrite if previous xmax aborted, or if it committed but
|
||||||
* but only locked the tuple without updating it.
|
* only locked the tuple without updating it.
|
||||||
*/
|
*/
|
||||||
if (oldtup.t_data->t_infomask & (HEAP_XMAX_INVALID |
|
if (oldtup.t_data->t_infomask & (HEAP_XMAX_INVALID |
|
||||||
HEAP_IS_LOCKED))
|
HEAP_IS_LOCKED))
|
||||||
|
@ -1753,15 +1750,15 @@ l2:
|
||||||
HeapTupleHeaderSetCmax(newtup->t_data, 0); /* for cleanliness */
|
HeapTupleHeaderSetCmax(newtup->t_data, 0); /* for cleanliness */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the toaster needs to be activated, OR if the new tuple will not
|
* If the toaster needs to be activated, OR if the new tuple will not fit
|
||||||
* fit on the same page as the old, then we need to release the
|
* on the same page as the old, then we need to release the context lock
|
||||||
* context lock (but not the pin!) on the old tuple's buffer while we
|
* (but not the pin!) on the old tuple's buffer while we are off doing
|
||||||
* are off doing TOAST and/or table-file-extension work. We must mark
|
* TOAST and/or table-file-extension work. We must mark the old tuple to
|
||||||
* the old tuple to show that it's already being updated, else other
|
* show that it's already being updated, else other processes may try to
|
||||||
* processes may try to update it themselves.
|
* update it themselves.
|
||||||
*
|
*
|
||||||
* We need to invoke the toaster if there are already any out-of-line
|
* We need to invoke the toaster if there are already any out-of-line toasted
|
||||||
* toasted values present, or if the new tuple is over-threshold.
|
* values present, or if the new tuple is over-threshold.
|
||||||
*/
|
*/
|
||||||
need_toast = (HeapTupleHasExternal(&oldtup) ||
|
need_toast = (HeapTupleHasExternal(&oldtup) ||
|
||||||
HeapTupleHasExternal(newtup) ||
|
HeapTupleHasExternal(newtup) ||
|
||||||
|
@ -1790,22 +1787,21 @@ l2:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now, do we need a new page for the tuple, or not? This is a
|
* Now, do we need a new page for the tuple, or not? This is a bit
|
||||||
* bit tricky since someone else could have added tuples to the
|
* tricky since someone else could have added tuples to the page while
|
||||||
* page while we weren't looking. We have to recheck the
|
* we weren't looking. We have to recheck the available space after
|
||||||
* available space after reacquiring the buffer lock. But don't
|
* reacquiring the buffer lock. But don't bother to do that if the
|
||||||
* bother to do that if the former amount of free space is still
|
* former amount of free space is still not enough; it's unlikely
|
||||||
* not enough; it's unlikely there's more free now than before.
|
* there's more free now than before.
|
||||||
*
|
*
|
||||||
* What's more, if we need to get a new page, we will need to acquire
|
* What's more, if we need to get a new page, we will need to acquire
|
||||||
* buffer locks on both old and new pages. To avoid deadlock
|
* buffer locks on both old and new pages. To avoid deadlock against
|
||||||
* against some other backend trying to get the same two locks in
|
* some other backend trying to get the same two locks in the other
|
||||||
* the other order, we must be consistent about the order we get
|
* order, we must be consistent about the order we get the locks in.
|
||||||
* the locks in. We use the rule "lock the lower-numbered page of
|
* We use the rule "lock the lower-numbered page of the relation
|
||||||
* the relation first". To implement this, we must do
|
* first". To implement this, we must do RelationGetBufferForTuple
|
||||||
* RelationGetBufferForTuple while not holding the lock on the old
|
* while not holding the lock on the old page, and we must rely on it
|
||||||
* page, and we must rely on it to get the locks on both pages in
|
* to get the locks on both pages in the correct order.
|
||||||
* the correct order.
|
|
||||||
*/
|
*/
|
||||||
if (newtupsize > pagefree)
|
if (newtupsize > pagefree)
|
||||||
{
|
{
|
||||||
|
@ -1823,8 +1819,8 @@ l2:
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Rats, it doesn't fit anymore. We must now unlock and
|
* Rats, it doesn't fit anymore. We must now unlock and
|
||||||
* relock to avoid deadlock. Fortunately, this path
|
* relock to avoid deadlock. Fortunately, this path should
|
||||||
* should seldom be taken.
|
* seldom be taken.
|
||||||
*/
|
*/
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
newbuf = RelationGetBufferForTuple(relation, newtup->t_len,
|
newbuf = RelationGetBufferForTuple(relation, newtup->t_len,
|
||||||
|
@ -1845,9 +1841,9 @@ l2:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At this point newbuf and buffer are both pinned and locked, and
|
* At this point newbuf and buffer are both pinned and locked, and newbuf
|
||||||
* newbuf has enough space for the new tuple. If they are the same
|
* has enough space for the new tuple. If they are the same buffer, only
|
||||||
* buffer, only one pin is held.
|
* one pin is held.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* NO EREPORT(ERROR) from here till changes are logged */
|
/* NO EREPORT(ERROR) from here till changes are logged */
|
||||||
|
@ -1897,8 +1893,8 @@ l2:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mark old tuple for invalidation from system caches at next command
|
* Mark old tuple for invalidation from system caches at next command
|
||||||
* boundary. We have to do this before WriteBuffer because we need to
|
* boundary. We have to do this before WriteBuffer because we need to look
|
||||||
* look at the contents of the tuple, so we need to hold our refcount.
|
* at the contents of the tuple, so we need to hold our refcount.
|
||||||
*/
|
*/
|
||||||
CacheInvalidateHeapTuple(relation, &oldtup);
|
CacheInvalidateHeapTuple(relation, &oldtup);
|
||||||
|
|
||||||
|
@ -1907,10 +1903,10 @@ l2:
|
||||||
WriteBuffer(buffer);
|
WriteBuffer(buffer);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If new tuple is cachable, mark it for invalidation from the caches
|
* If new tuple is cachable, mark it for invalidation from the caches in
|
||||||
* in case we abort. Note it is OK to do this after WriteBuffer
|
* case we abort. Note it is OK to do this after WriteBuffer releases the
|
||||||
* releases the buffer, because the "newtup" data structure is all in
|
* buffer, because the "newtup" data structure is all in local memory, not
|
||||||
* local memory, not in the shared buffer.
|
* in the shared buffer.
|
||||||
*/
|
*/
|
||||||
CacheInvalidateHeapTuple(relation, newtup);
|
CacheInvalidateHeapTuple(relation, newtup);
|
||||||
|
|
||||||
|
@ -2077,12 +2073,12 @@ l3:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire tuple lock to establish our priority for the tuple.
|
* Acquire tuple lock to establish our priority for the tuple.
|
||||||
* LockTuple will release us when we are next-in-line for the
|
* LockTuple will release us when we are next-in-line for the tuple.
|
||||||
* tuple. We must do this even if we are share-locking.
|
* We must do this even if we are share-locking.
|
||||||
*
|
*
|
||||||
* If we are forced to "start over" below, we keep the tuple lock;
|
* If we are forced to "start over" below, we keep the tuple lock; this
|
||||||
* this arranges that we stay at the head of the line while
|
* arranges that we stay at the head of the line while rechecking
|
||||||
* rechecking tuple state.
|
* tuple state.
|
||||||
*/
|
*/
|
||||||
if (!have_tuple_lock)
|
if (!have_tuple_lock)
|
||||||
{
|
{
|
||||||
|
@ -2108,8 +2104,8 @@ l3:
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make sure it's still a shared lock, else start over. (It's
|
* Make sure it's still a shared lock, else start over. (It's OK
|
||||||
* OK if the ownership of the shared lock has changed, though.)
|
* if the ownership of the shared lock has changed, though.)
|
||||||
*/
|
*/
|
||||||
if (!(tuple->t_data->t_infomask & HEAP_XMAX_SHARED_LOCK))
|
if (!(tuple->t_data->t_infomask & HEAP_XMAX_SHARED_LOCK))
|
||||||
goto l3;
|
goto l3;
|
||||||
|
@ -2131,9 +2127,9 @@ l3:
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If xwait had just locked the tuple then some other xact
|
* If xwait had just locked the tuple then some other xact could
|
||||||
* could update this tuple before we get to this point.
|
* update this tuple before we get to this point. Check for xmax
|
||||||
* Check for xmax change, and start over if so.
|
* change, and start over if so.
|
||||||
*/
|
*/
|
||||||
if (!(tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
if (!(tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
||||||
!TransactionIdEquals(HeapTupleHeaderGetXmax(tuple->t_data),
|
!TransactionIdEquals(HeapTupleHeaderGetXmax(tuple->t_data),
|
||||||
|
@ -2141,12 +2137,12 @@ l3:
|
||||||
goto l3;
|
goto l3;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* You might think the multixact is necessarily done here, but
|
* You might think the multixact is necessarily done here, but not
|
||||||
* not so: it could have surviving members, namely our own xact
|
* so: it could have surviving members, namely our own xact or
|
||||||
* or other subxacts of this backend. It is legal for us to
|
* other subxacts of this backend. It is legal for us to lock the
|
||||||
* lock the tuple in either case, however. We don't bother
|
* tuple in either case, however. We don't bother changing the
|
||||||
* changing the on-disk hint bits since we are about to
|
* on-disk hint bits since we are about to overwrite the xmax
|
||||||
* overwrite the xmax altogether.
|
* altogether.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -2166,9 +2162,9 @@ l3:
|
||||||
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(*buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* xwait is done, but if xwait had just locked the tuple then
|
* xwait is done, but if xwait had just locked the tuple then some
|
||||||
* some other xact could update this tuple before we get to
|
* other xact could update this tuple before we get to this point.
|
||||||
* this point. Check for xmax change, and start over if so.
|
* Check for xmax change, and start over if so.
|
||||||
*/
|
*/
|
||||||
if ((tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
if ((tuple->t_data->t_infomask & HEAP_XMAX_IS_MULTI) ||
|
||||||
!TransactionIdEquals(HeapTupleHeaderGetXmax(tuple->t_data),
|
!TransactionIdEquals(HeapTupleHeaderGetXmax(tuple->t_data),
|
||||||
|
@ -2188,10 +2184,10 @@ l3:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We may lock if previous xmax aborted, or if it committed
|
* We may lock if previous xmax aborted, or if it committed but only
|
||||||
* but only locked the tuple without updating it. The case where
|
* locked the tuple without updating it. The case where we didn't
|
||||||
* we didn't wait because we are joining an existing shared lock
|
* wait because we are joining an existing shared lock is correctly
|
||||||
* is correctly handled, too.
|
* handled, too.
|
||||||
*/
|
*/
|
||||||
if (tuple->t_data->t_infomask & (HEAP_XMAX_INVALID |
|
if (tuple->t_data->t_infomask & (HEAP_XMAX_INVALID |
|
||||||
HEAP_IS_LOCKED))
|
HEAP_IS_LOCKED))
|
||||||
|
@ -2213,9 +2209,9 @@ l3:
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute the new xmax and infomask to store into the tuple. Note we
|
* Compute the new xmax and infomask to store into the tuple. Note we do
|
||||||
* do not modify the tuple just yet, because that would leave it in the
|
* not modify the tuple just yet, because that would leave it in the wrong
|
||||||
* wrong state if multixact.c elogs.
|
* state if multixact.c elogs.
|
||||||
*/
|
*/
|
||||||
xid = GetCurrentTransactionId();
|
xid = GetCurrentTransactionId();
|
||||||
|
|
||||||
|
@ -2234,12 +2230,11 @@ l3:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this is the first acquisition of a shared lock in the current
|
* If this is the first acquisition of a shared lock in the current
|
||||||
* transaction, set my per-backend OldestMemberMXactId setting.
|
* transaction, set my per-backend OldestMemberMXactId setting. We can
|
||||||
* We can be certain that the transaction will never become a
|
* be certain that the transaction will never become a member of any
|
||||||
* member of any older MultiXactIds than that. (We have to do this
|
* older MultiXactIds than that. (We have to do this even if we end
|
||||||
* even if we end up just using our own TransactionId below, since
|
* up just using our own TransactionId below, since some other backend
|
||||||
* some other backend could incorporate our XID into a MultiXact
|
* could incorporate our XID into a MultiXact immediately afterwards.)
|
||||||
* immediately afterwards.)
|
|
||||||
*/
|
*/
|
||||||
MultiXactIdSetOldestMember();
|
MultiXactIdSetOldestMember();
|
||||||
|
|
||||||
|
@ -2249,14 +2244,14 @@ l3:
|
||||||
* Check to see if we need a MultiXactId because there are multiple
|
* Check to see if we need a MultiXactId because there are multiple
|
||||||
* lockers.
|
* lockers.
|
||||||
*
|
*
|
||||||
* HeapTupleSatisfiesUpdate will have set the HEAP_XMAX_INVALID
|
* HeapTupleSatisfiesUpdate will have set the HEAP_XMAX_INVALID bit if
|
||||||
* bit if the xmax was a MultiXactId but it was not running anymore.
|
* the xmax was a MultiXactId but it was not running anymore. There is
|
||||||
* There is a race condition, which is that the MultiXactId may have
|
* a race condition, which is that the MultiXactId may have finished
|
||||||
* finished since then, but that uncommon case is handled within
|
* since then, but that uncommon case is handled within
|
||||||
* MultiXactIdExpand.
|
* MultiXactIdExpand.
|
||||||
*
|
*
|
||||||
* There is a similar race condition possible when the old xmax was
|
* There is a similar race condition possible when the old xmax was a
|
||||||
* a regular TransactionId. We test TransactionIdIsInProgress again
|
* regular TransactionId. We test TransactionIdIsInProgress again
|
||||||
* just to narrow the window, but it's still possible to end up
|
* just to narrow the window, but it's still possible to end up
|
||||||
* creating an unnecessary MultiXactId. Fortunately this is harmless.
|
* creating an unnecessary MultiXactId. Fortunately this is harmless.
|
||||||
*/
|
*/
|
||||||
|
@ -2278,9 +2273,9 @@ l3:
|
||||||
/*
|
/*
|
||||||
* If the old locker is ourselves, we'll just mark the
|
* If the old locker is ourselves, we'll just mark the
|
||||||
* tuple again with our own TransactionId. However we
|
* tuple again with our own TransactionId. However we
|
||||||
* have to consider the possibility that we had
|
* have to consider the possibility that we had exclusive
|
||||||
* exclusive rather than shared lock before --- if so,
|
* rather than shared lock before --- if so, be careful to
|
||||||
* be careful to preserve the exclusivity of the lock.
|
* preserve the exclusivity of the lock.
|
||||||
*/
|
*/
|
||||||
if (!(old_infomask & HEAP_XMAX_SHARED_LOCK))
|
if (!(old_infomask & HEAP_XMAX_SHARED_LOCK))
|
||||||
{
|
{
|
||||||
|
@ -2303,8 +2298,8 @@ l3:
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Can get here iff HeapTupleSatisfiesUpdate saw the old
|
* Can get here iff HeapTupleSatisfiesUpdate saw the old xmax
|
||||||
* xmax as running, but it finished before
|
* as running, but it finished before
|
||||||
* TransactionIdIsInProgress() got to run. Treat it like
|
* TransactionIdIsInProgress() got to run. Treat it like
|
||||||
* there's no locker in the tuple.
|
* there's no locker in the tuple.
|
||||||
*/
|
*/
|
||||||
|
@ -2329,8 +2324,8 @@ l3:
|
||||||
/*
|
/*
|
||||||
* Store transaction information of xact locking the tuple.
|
* Store transaction information of xact locking the tuple.
|
||||||
*
|
*
|
||||||
* Note: our CID is meaningless if storing a MultiXactId, but no harm
|
* Note: our CID is meaningless if storing a MultiXactId, but no harm in
|
||||||
* in storing it anyway.
|
* storing it anyway.
|
||||||
*/
|
*/
|
||||||
tuple->t_data->t_infomask = new_infomask;
|
tuple->t_data->t_infomask = new_infomask;
|
||||||
HeapTupleHeaderSetXmax(tuple->t_data, xid);
|
HeapTupleHeaderSetXmax(tuple->t_data, xid);
|
||||||
|
@ -2473,8 +2468,8 @@ log_heap_clean(Relation reln, Buffer buffer, OffsetNumber *unused, int uncnt)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The unused-offsets array is not actually in the buffer, but pretend
|
* The unused-offsets array is not actually in the buffer, but pretend
|
||||||
* that it is. When XLogInsert stores the whole buffer, the offsets
|
* that it is. When XLogInsert stores the whole buffer, the offsets array
|
||||||
* array need not be stored too.
|
* need not be stored too.
|
||||||
*/
|
*/
|
||||||
if (uncnt > 0)
|
if (uncnt > 0)
|
||||||
{
|
{
|
||||||
|
@ -2500,11 +2495,10 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||||
Buffer newbuf, HeapTuple newtup, bool move)
|
Buffer newbuf, HeapTuple newtup, bool move)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Note: xlhdr is declared to have adequate size and correct alignment
|
* Note: xlhdr is declared to have adequate size and correct alignment for
|
||||||
* for an xl_heap_header. However the two tids, if present at all,
|
* an xl_heap_header. However the two tids, if present at all, will be
|
||||||
* will be packed in with no wasted space after the xl_heap_header;
|
* packed in with no wasted space after the xl_heap_header; they aren't
|
||||||
* they aren't necessarily aligned as implied by this struct
|
* necessarily aligned as implied by this struct declaration.
|
||||||
* declaration.
|
|
||||||
*/
|
*/
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
|
@ -2555,8 +2549,8 @@ log_heap_update(Relation reln, Buffer oldbuf, ItemPointerData from,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As with insert records, we need not store the rdata[2] segment if
|
* As with insert records, we need not store the rdata[2] segment if we
|
||||||
* we decide to store the whole buffer instead.
|
* decide to store the whole buffer instead.
|
||||||
*/
|
*/
|
||||||
rdata[2].data = (char *) &xlhdr;
|
rdata[2].data = (char *) &xlhdr;
|
||||||
rdata[2].len = hsize;
|
rdata[2].len = hsize;
|
||||||
|
@ -2655,8 +2649,8 @@ heap_xlog_newpage(XLogRecPtr lsn, XLogRecord *record)
|
||||||
Page page;
|
Page page;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Note: the NEWPAGE log record is used for both heaps and indexes, so
|
* Note: the NEWPAGE log record is used for both heaps and indexes, so do
|
||||||
* do not do anything that assumes we are touching a heap.
|
* not do anything that assumes we are touching a heap.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (record->xl_info & XLR_BKP_BLOCK_1)
|
if (record->xl_info & XLR_BKP_BLOCK_1)
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.57 2005/06/20 18:37:01 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/heap/hio.c,v 1.58 2005/10/15 02:49:08 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -122,22 +122,20 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
if (otherBuffer != InvalidBuffer)
|
if (otherBuffer != InvalidBuffer)
|
||||||
otherBlock = BufferGetBlockNumber(otherBuffer);
|
otherBlock = BufferGetBlockNumber(otherBuffer);
|
||||||
else
|
else
|
||||||
otherBlock = InvalidBlockNumber; /* just to keep compiler
|
otherBlock = InvalidBlockNumber; /* just to keep compiler quiet */
|
||||||
* quiet */
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We first try to put the tuple on the same page we last inserted a
|
* We first try to put the tuple on the same page we last inserted a tuple
|
||||||
* tuple on, as cached in the relcache entry. If that doesn't work,
|
* on, as cached in the relcache entry. If that doesn't work, we ask the
|
||||||
* we ask the shared Free Space Map to locate a suitable page. Since
|
* shared Free Space Map to locate a suitable page. Since the FSM's info
|
||||||
* the FSM's info might be out of date, we have to be prepared to loop
|
* might be out of date, we have to be prepared to loop around and retry
|
||||||
* around and retry multiple times. (To insure this isn't an infinite
|
* multiple times. (To insure this isn't an infinite loop, we must update
|
||||||
* loop, we must update the FSM with the correct amount of free space
|
* the FSM with the correct amount of free space on each page that proves
|
||||||
* on each page that proves not to be suitable.) If the FSM has no
|
* not to be suitable.) If the FSM has no record of a page with enough
|
||||||
* record of a page with enough free space, we give up and extend the
|
* free space, we give up and extend the relation.
|
||||||
* relation.
|
|
||||||
*
|
*
|
||||||
* When use_fsm is false, we either put the tuple onto the existing
|
* When use_fsm is false, we either put the tuple onto the existing target
|
||||||
* target page or extend the relation.
|
* page or extend the relation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
targetBlock = relation->rd_targblock;
|
targetBlock = relation->rd_targblock;
|
||||||
|
@ -151,9 +149,9 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
targetBlock = GetPageWithFreeSpace(&relation->rd_node, len);
|
targetBlock = GetPageWithFreeSpace(&relation->rd_node, len);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the FSM knows nothing of the rel, try the last page before
|
* If the FSM knows nothing of the rel, try the last page before we
|
||||||
* we give up and extend. This avoids one-tuple-per-page syndrome
|
* give up and extend. This avoids one-tuple-per-page syndrome during
|
||||||
* during bootstrapping or in a recently-started system.
|
* bootstrapping or in a recently-started system.
|
||||||
*/
|
*/
|
||||||
if (targetBlock == InvalidBlockNumber)
|
if (targetBlock == InvalidBlockNumber)
|
||||||
{
|
{
|
||||||
|
@ -168,8 +166,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Read and exclusive-lock the target block, as well as the other
|
* Read and exclusive-lock the target block, as well as the other
|
||||||
* block if one was given, taking suitable care with lock ordering
|
* block if one was given, taking suitable care with lock ordering and
|
||||||
* and the possibility they are the same block.
|
* the possibility they are the same block.
|
||||||
*/
|
*/
|
||||||
if (otherBuffer == InvalidBuffer)
|
if (otherBuffer == InvalidBuffer)
|
||||||
{
|
{
|
||||||
|
@ -199,8 +197,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we can check to see if there's enough free space here. If
|
* Now we can check to see if there's enough free space here. If so,
|
||||||
* so, we're done.
|
* we're done.
|
||||||
*/
|
*/
|
||||||
pageHeader = (Page) BufferGetPage(buffer);
|
pageHeader = (Page) BufferGetPage(buffer);
|
||||||
pageFreeSpace = PageGetFreeSpace(pageHeader);
|
pageFreeSpace = PageGetFreeSpace(pageHeader);
|
||||||
|
@ -213,9 +211,9 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not enough space, so we must give up our page locks and pin (if
|
* Not enough space, so we must give up our page locks and pin (if
|
||||||
* any) and prepare to look elsewhere. We don't care which order
|
* any) and prepare to look elsewhere. We don't care which order we
|
||||||
* we unlock the two buffers in, so this can be slightly simpler
|
* unlock the two buffers in, so this can be slightly simpler than the
|
||||||
* than the code above.
|
* code above.
|
||||||
*/
|
*/
|
||||||
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
|
||||||
if (otherBuffer == InvalidBuffer)
|
if (otherBuffer == InvalidBuffer)
|
||||||
|
@ -231,8 +229,8 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update FSM as to condition of this page, and ask for another
|
* Update FSM as to condition of this page, and ask for another page
|
||||||
* page to try.
|
* to try.
|
||||||
*/
|
*/
|
||||||
targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node,
|
targetBlock = RecordAndGetPageWithFreeSpace(&relation->rd_node,
|
||||||
targetBlock,
|
targetBlock,
|
||||||
|
@ -243,10 +241,10 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
/*
|
/*
|
||||||
* Have to extend the relation.
|
* Have to extend the relation.
|
||||||
*
|
*
|
||||||
* We have to use a lock to ensure no one else is extending the rel at
|
* We have to use a lock to ensure no one else is extending the rel at the
|
||||||
* the same time, else we will both try to initialize the same new
|
* same time, else we will both try to initialize the same new page. We
|
||||||
* page. We can skip locking for new or temp relations, however,
|
* can skip locking for new or temp relations, however, since no one else
|
||||||
* since no one else could be accessing them.
|
* could be accessing them.
|
||||||
*/
|
*/
|
||||||
needLock = !RELATION_IS_LOCAL(relation);
|
needLock = !RELATION_IS_LOCAL(relation);
|
||||||
|
|
||||||
|
@ -254,17 +252,16 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
LockRelationForExtension(relation, ExclusiveLock);
|
LockRelationForExtension(relation, ExclusiveLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* XXX This does an lseek - rather expensive - but at the moment it is
|
* XXX This does an lseek - rather expensive - but at the moment it is the
|
||||||
* the only way to accurately determine how many blocks are in a
|
* only way to accurately determine how many blocks are in a relation. Is
|
||||||
* relation. Is it worth keeping an accurate file length in shared
|
* it worth keeping an accurate file length in shared memory someplace,
|
||||||
* memory someplace, rather than relying on the kernel to do it for
|
* rather than relying on the kernel to do it for us?
|
||||||
* us?
|
|
||||||
*/
|
*/
|
||||||
buffer = ReadBuffer(relation, P_NEW);
|
buffer = ReadBuffer(relation, P_NEW);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can be certain that locking the otherBuffer first is OK, since
|
* We can be certain that locking the otherBuffer first is OK, since it
|
||||||
* it must have a lower page number.
|
* must have a lower page number.
|
||||||
*/
|
*/
|
||||||
if (otherBuffer != InvalidBuffer)
|
if (otherBuffer != InvalidBuffer)
|
||||||
LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(otherBuffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
@ -275,10 +272,10 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
LockBuffer(buffer, BUFFER_LOCK_EXCLUSIVE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Release the file-extension lock; it's now OK for someone else to
|
* Release the file-extension lock; it's now OK for someone else to extend
|
||||||
* extend the relation some more. Note that we cannot release this
|
* the relation some more. Note that we cannot release this lock before
|
||||||
* lock before we have buffer lock on the new page, or we risk a
|
* we have buffer lock on the new page, or we risk a race condition
|
||||||
* race condition against vacuumlazy.c --- see comments therein.
|
* against vacuumlazy.c --- see comments therein.
|
||||||
*/
|
*/
|
||||||
if (needLock)
|
if (needLock)
|
||||||
UnlockRelationForExtension(relation, ExclusiveLock);
|
UnlockRelationForExtension(relation, ExclusiveLock);
|
||||||
|
@ -299,11 +296,11 @@ RelationGetBufferForTuple(Relation relation, Size len,
|
||||||
/*
|
/*
|
||||||
* Remember the new page as our target for future insertions.
|
* Remember the new page as our target for future insertions.
|
||||||
*
|
*
|
||||||
* XXX should we enter the new page into the free space map immediately,
|
* XXX should we enter the new page into the free space map immediately, or
|
||||||
* or just keep it for this backend's exclusive use in the short run
|
* just keep it for this backend's exclusive use in the short run (until
|
||||||
* (until VACUUM sees it)? Seems to depend on whether you expect the
|
* VACUUM sees it)? Seems to depend on whether you expect the current
|
||||||
* current backend to make more insertions or not, which is probably a
|
* backend to make more insertions or not, which is probably a good bet
|
||||||
* good bet most of the time. So for now, don't add it to FSM yet.
|
* most of the time. So for now, don't add it to FSM yet.
|
||||||
*/
|
*/
|
||||||
relation->rd_targblock = BufferGetBlockNumber(buffer);
|
relation->rd_targblock = BufferGetBlockNumber(buffer);
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.52 2005/08/12 01:35:54 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.53 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
|
@ -90,8 +90,7 @@ heap_tuple_fetch_attr(varattrib *attr)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is a plain value inside of the main tuple - why am I
|
* This is a plain value inside of the main tuple - why am I called?
|
||||||
* called?
|
|
||||||
*/
|
*/
|
||||||
result = attr;
|
result = attr;
|
||||||
}
|
}
|
||||||
|
@ -154,8 +153,7 @@ heap_tuple_untoast_attr(varattrib *attr)
|
||||||
else
|
else
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is a plain value inside of the main tuple - why am I
|
* This is a plain value inside of the main tuple - why am I called?
|
||||||
* called?
|
|
||||||
*/
|
*/
|
||||||
return attr;
|
return attr;
|
||||||
|
|
||||||
|
@ -255,8 +253,8 @@ toast_raw_datum_size(Datum value)
|
||||||
else if (VARATT_IS_EXTERNAL(attr))
|
else if (VARATT_IS_EXTERNAL(attr))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* an uncompressed external attribute has rawsize including the
|
* an uncompressed external attribute has rawsize including the header
|
||||||
* header (not too consistent!)
|
* (not too consistent!)
|
||||||
*/
|
*/
|
||||||
result = attr->va_content.va_external.va_rawsize;
|
result = attr->va_content.va_external.va_rawsize;
|
||||||
}
|
}
|
||||||
|
@ -284,16 +282,16 @@ toast_datum_size(Datum value)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Attribute is stored externally - return the extsize whether
|
* Attribute is stored externally - return the extsize whether
|
||||||
* compressed or not. We do not count the size of the toast
|
* compressed or not. We do not count the size of the toast pointer
|
||||||
* pointer ... should we?
|
* ... should we?
|
||||||
*/
|
*/
|
||||||
result = attr->va_content.va_external.va_extsize;
|
result = attr->va_content.va_external.va_extsize;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Attribute is stored inline either compressed or not, just
|
* Attribute is stored inline either compressed or not, just calculate
|
||||||
* calculate the size of the datum in either case.
|
* the size of the datum in either case.
|
||||||
*/
|
*/
|
||||||
result = VARSIZE(attr);
|
result = VARSIZE(attr);
|
||||||
}
|
}
|
||||||
|
@ -321,12 +319,12 @@ toast_delete(Relation rel, HeapTuple oldtup)
|
||||||
* Get the tuple descriptor and break down the tuple into fields.
|
* Get the tuple descriptor and break down the tuple into fields.
|
||||||
*
|
*
|
||||||
* NOTE: it's debatable whether to use heap_deformtuple() here or just
|
* NOTE: it's debatable whether to use heap_deformtuple() here or just
|
||||||
* heap_getattr() only the varlena columns. The latter could win if
|
* heap_getattr() only the varlena columns. The latter could win if there
|
||||||
* there are few varlena columns and many non-varlena ones. However,
|
* are few varlena columns and many non-varlena ones. However,
|
||||||
* heap_deformtuple costs only O(N) while the heap_getattr way would
|
* heap_deformtuple costs only O(N) while the heap_getattr way would cost
|
||||||
* cost O(N^2) if there are many varlena columns, so it seems better
|
* O(N^2) if there are many varlena columns, so it seems better to err on
|
||||||
* to err on the side of linear cost. (We won't even be here unless
|
* the side of linear cost. (We won't even be here unless there's at
|
||||||
* there's at least one varlena column, by the way.)
|
* least one varlena column, by the way.)
|
||||||
*/
|
*/
|
||||||
tupleDesc = rel->rd_att;
|
tupleDesc = rel->rd_att;
|
||||||
att = tupleDesc->attrs;
|
att = tupleDesc->attrs;
|
||||||
|
@ -336,8 +334,8 @@ toast_delete(Relation rel, HeapTuple oldtup)
|
||||||
heap_deform_tuple(oldtup, tupleDesc, toast_values, toast_isnull);
|
heap_deform_tuple(oldtup, tupleDesc, toast_values, toast_isnull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check for external stored attributes and delete them from the
|
* Check for external stored attributes and delete them from the secondary
|
||||||
* secondary relation.
|
* relation.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < numAttrs; i++)
|
for (i = 0; i < numAttrs; i++)
|
||||||
{
|
{
|
||||||
|
@ -447,9 +445,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This attribute isn't changed by this update so we
|
* This attribute isn't changed by this update so we reuse
|
||||||
* reuse the original reference to the old value in
|
* the original reference to the old value in the new
|
||||||
* the new tuple.
|
* tuple.
|
||||||
*/
|
*/
|
||||||
toast_action[i] = 'p';
|
toast_action[i] = 'p';
|
||||||
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
toast_sizes[i] = VARATT_SIZE(toast_values[i]);
|
||||||
|
@ -582,16 +580,15 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* incompressible data, ignore on subsequent compression
|
* incompressible data, ignore on subsequent compression passes
|
||||||
* passes
|
|
||||||
*/
|
*/
|
||||||
toast_action[i] = 'x';
|
toast_action[i] = 'x';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Second we look for attributes of attstorage 'x' or 'e' that are
|
* Second we look for attributes of attstorage 'x' or 'e' that are still
|
||||||
* still inline.
|
* inline.
|
||||||
*/
|
*/
|
||||||
while (MAXALIGN(heap_compute_data_size(tupleDesc,
|
while (MAXALIGN(heap_compute_data_size(tupleDesc,
|
||||||
toast_values, toast_isnull)) >
|
toast_values, toast_isnull)) >
|
||||||
|
@ -696,8 +693,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* incompressible data, ignore on subsequent compression
|
* incompressible data, ignore on subsequent compression passes
|
||||||
* passes
|
|
||||||
*/
|
*/
|
||||||
toast_action[i] = 'x';
|
toast_action[i] = 'x';
|
||||||
}
|
}
|
||||||
|
@ -755,8 +751,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the case we toasted any values, we need to build a new heap
|
* In the case we toasted any values, we need to build a new heap tuple
|
||||||
* tuple with the changed values.
|
* with the changed values.
|
||||||
*/
|
*/
|
||||||
if (need_change)
|
if (need_change)
|
||||||
{
|
{
|
||||||
|
@ -798,8 +794,8 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup)
|
||||||
has_nulls ? newtup->t_data->t_bits : NULL);
|
has_nulls ? newtup->t_data->t_bits : NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* In the case we modified a previously modified tuple again, free
|
* In the case we modified a previously modified tuple again, free the
|
||||||
* the memory from the previous run
|
* memory from the previous run
|
||||||
*/
|
*/
|
||||||
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
if ((char *) olddata != ((char *) newtup + HEAPTUPLESIZE))
|
||||||
pfree(olddata);
|
pfree(olddata);
|
||||||
|
@ -906,8 +902,8 @@ toast_flatten_tuple_attribute(Datum value,
|
||||||
return value;
|
return value;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate the new size of the tuple. Header size should not
|
* Calculate the new size of the tuple. Header size should not change,
|
||||||
* change, but data size might.
|
* but data size might.
|
||||||
*/
|
*/
|
||||||
new_len = offsetof(HeapTupleHeaderData, t_bits);
|
new_len = offsetof(HeapTupleHeaderData, t_bits);
|
||||||
if (has_nulls)
|
if (has_nulls)
|
||||||
|
@ -1007,9 +1003,9 @@ toast_save_datum(Relation rel, Datum value)
|
||||||
int32 data_todo;
|
int32 data_todo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Open the toast relation and its index. We can use the index to
|
* Open the toast relation and its index. We can use the index to check
|
||||||
* check uniqueness of the OID we assign to the toasted item, even
|
* uniqueness of the OID we assign to the toasted item, even though it has
|
||||||
* though it has additional columns besides OID.
|
* additional columns besides OID.
|
||||||
*/
|
*/
|
||||||
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
toastrel = heap_open(rel->rd_rel->reltoastrelid, RowExclusiveLock);
|
||||||
toasttupDesc = toastrel->rd_att;
|
toasttupDesc = toastrel->rd_att;
|
||||||
|
@ -1082,11 +1078,11 @@ toast_save_datum(Relation rel, Datum value)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the index entry. We cheat a little here by not using
|
* Create the index entry. We cheat a little here by not using
|
||||||
* FormIndexDatum: this relies on the knowledge that the index
|
* FormIndexDatum: this relies on the knowledge that the index columns
|
||||||
* columns are the same as the initial columns of the table.
|
* are the same as the initial columns of the table.
|
||||||
*
|
*
|
||||||
* Note also that there had better not be any user-created index on
|
* Note also that there had better not be any user-created index on the
|
||||||
* the TOAST table, since we don't bother to update anything else.
|
* TOAST table, since we don't bother to update anything else.
|
||||||
*/
|
*/
|
||||||
index_insert(toastidx, t_values, t_isnull,
|
index_insert(toastidx, t_values, t_isnull,
|
||||||
&(toasttup->t_self),
|
&(toasttup->t_self),
|
||||||
|
@ -1224,9 +1220,9 @@ toast_fetch_datum(varattrib *attr)
|
||||||
/*
|
/*
|
||||||
* Read the chunks by index
|
* Read the chunks by index
|
||||||
*
|
*
|
||||||
* Note that because the index is actually on (valueid, chunkidx) we will
|
* Note that because the index is actually on (valueid, chunkidx) we will see
|
||||||
* see the chunks in chunkidx order, even though we didn't explicitly
|
* the chunks in chunkidx order, even though we didn't explicitly ask for
|
||||||
* ask for it.
|
* it.
|
||||||
*/
|
*/
|
||||||
nextidx = 0;
|
nextidx = 0;
|
||||||
|
|
||||||
|
@ -1367,8 +1363,8 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length)
|
||||||
toastidx = index_open(toastrel->rd_rel->reltoastidxid);
|
toastidx = index_open(toastrel->rd_rel->reltoastidxid);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup a scan key to fetch from the index. This is either two keys
|
* Setup a scan key to fetch from the index. This is either two keys or
|
||||||
* or three depending on the number of chunks.
|
* three depending on the number of chunks.
|
||||||
*/
|
*/
|
||||||
ScanKeyInit(&toastkey[0],
|
ScanKeyInit(&toastkey[0],
|
||||||
(AttrNumber) 1,
|
(AttrNumber) 1,
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.48 2005/05/27 23:31:20 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/index/genam.c,v 1.49 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* many of the old access method routines have been turned into
|
* many of the old access method routines have been turned into
|
||||||
|
@ -78,8 +78,8 @@ RelationGetIndexScan(Relation indexRelation,
|
||||||
scan->numberOfKeys = nkeys;
|
scan->numberOfKeys = nkeys;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We allocate the key space here, but the AM is responsible for
|
* We allocate the key space here, but the AM is responsible for actually
|
||||||
* actually filling it from the passed key array.
|
* filling it from the passed key array.
|
||||||
*/
|
*/
|
||||||
if (nkeys > 0)
|
if (nkeys > 0)
|
||||||
scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
|
scan->keyData = (ScanKey) palloc(sizeof(ScanKeyData) * nkeys);
|
||||||
|
@ -203,8 +203,8 @@ systable_beginscan(Relation heapRelation,
|
||||||
/*
|
/*
|
||||||
* Change attribute numbers to be index column numbers.
|
* Change attribute numbers to be index column numbers.
|
||||||
*
|
*
|
||||||
* This code could be generalized to search for the index key numbers
|
* This code could be generalized to search for the index key numbers to
|
||||||
* to substitute, but for now there's no need.
|
* substitute, but for now there's no need.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < nkeys; i++)
|
for (i = 0; i < nkeys; i++)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.85 2005/10/06 02:29:11 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/index/indexam.c,v 1.86 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
* INTERFACE ROUTINES
|
* INTERFACE ROUTINES
|
||||||
* index_open - open an index relation by relation OID
|
* index_open - open an index relation by relation OID
|
||||||
|
@ -241,8 +241,8 @@ index_beginscan(Relation heapRelation,
|
||||||
scan = index_beginscan_internal(indexRelation, nkeys, key);
|
scan = index_beginscan_internal(indexRelation, nkeys, key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save additional parameters into the scandesc. Everything else was
|
* Save additional parameters into the scandesc. Everything else was set
|
||||||
* set up by RelationGetIndexScan.
|
* up by RelationGetIndexScan.
|
||||||
*/
|
*/
|
||||||
scan->is_multiscan = false;
|
scan->is_multiscan = false;
|
||||||
scan->heapRelation = heapRelation;
|
scan->heapRelation = heapRelation;
|
||||||
|
@ -267,8 +267,8 @@ index_beginscan_multi(Relation indexRelation,
|
||||||
scan = index_beginscan_internal(indexRelation, nkeys, key);
|
scan = index_beginscan_internal(indexRelation, nkeys, key);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save additional parameters into the scandesc. Everything else was
|
* Save additional parameters into the scandesc. Everything else was set
|
||||||
* set up by RelationGetIndexScan.
|
* up by RelationGetIndexScan.
|
||||||
*/
|
*/
|
||||||
scan->is_multiscan = true;
|
scan->is_multiscan = true;
|
||||||
scan->xs_snapshot = snapshot;
|
scan->xs_snapshot = snapshot;
|
||||||
|
@ -294,14 +294,14 @@ index_beginscan_internal(Relation indexRelation,
|
||||||
* Acquire AccessShareLock for the duration of the scan
|
* Acquire AccessShareLock for the duration of the scan
|
||||||
*
|
*
|
||||||
* Note: we could get an SI inval message here and consequently have to
|
* Note: we could get an SI inval message here and consequently have to
|
||||||
* rebuild the relcache entry. The refcount increment above ensures
|
* rebuild the relcache entry. The refcount increment above ensures that
|
||||||
* that we will rebuild it and not just flush it...
|
* we will rebuild it and not just flush it...
|
||||||
*/
|
*/
|
||||||
LockRelation(indexRelation, AccessShareLock);
|
LockRelation(indexRelation, AccessShareLock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* LockRelation can clean rd_aminfo structure, so fill procedure
|
* LockRelation can clean rd_aminfo structure, so fill procedure after
|
||||||
* after LockRelation
|
* LockRelation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
GET_REL_PROCEDURE(ambeginscan);
|
GET_REL_PROCEDURE(ambeginscan);
|
||||||
|
@ -425,8 +425,8 @@ index_restrpos(IndexScanDesc scan)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We do not reset got_tuple; so if the scan is actually being
|
* We do not reset got_tuple; so if the scan is actually being
|
||||||
* short-circuited by index_getnext, the effective position
|
* short-circuited by index_getnext, the effective position restoration is
|
||||||
* restoration is done by restoring unique_tuple_pos.
|
* done by restoring unique_tuple_pos.
|
||||||
*/
|
*/
|
||||||
scan->unique_tuple_pos = scan->unique_tuple_mark;
|
scan->unique_tuple_pos = scan->unique_tuple_mark;
|
||||||
|
|
||||||
|
@ -454,19 +454,19 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we already got a tuple and it must be unique, there's no need to
|
* If we already got a tuple and it must be unique, there's no need to
|
||||||
* make the index AM look through any additional tuples. (This can
|
* make the index AM look through any additional tuples. (This can save a
|
||||||
* save a useful amount of work in scenarios where there are many dead
|
* useful amount of work in scenarios where there are many dead tuples due
|
||||||
* tuples due to heavy update activity.)
|
* to heavy update activity.)
|
||||||
*
|
*
|
||||||
* To do this we must keep track of the logical scan position
|
* To do this we must keep track of the logical scan position
|
||||||
* (before/on/after tuple). Also, we have to be sure to release scan
|
* (before/on/after tuple). Also, we have to be sure to release scan
|
||||||
* resources before returning NULL; if we fail to do so then a
|
* resources before returning NULL; if we fail to do so then a multi-index
|
||||||
* multi-index scan can easily run the system out of free buffers. We
|
* scan can easily run the system out of free buffers. We can release
|
||||||
* can release index-level resources fairly cheaply by calling
|
* index-level resources fairly cheaply by calling index_rescan. This
|
||||||
* index_rescan. This means there are two persistent states as far as
|
* means there are two persistent states as far as the index AM is
|
||||||
* the index AM is concerned: on-tuple and rescanned. If we are
|
* concerned: on-tuple and rescanned. If we are actually asked to
|
||||||
* actually asked to re-fetch the single tuple, we have to go through
|
* re-fetch the single tuple, we have to go through a fresh indexscan
|
||||||
* a fresh indexscan startup, which penalizes that (infrequent) case.
|
* startup, which penalizes that (infrequent) case.
|
||||||
*/
|
*/
|
||||||
if (scan->keys_are_unique && scan->got_tuple)
|
if (scan->keys_are_unique && scan->got_tuple)
|
||||||
{
|
{
|
||||||
|
@ -485,19 +485,18 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
||||||
if (new_tuple_pos == 0)
|
if (new_tuple_pos == 0)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We are moving onto the unique tuple from having been off
|
* We are moving onto the unique tuple from having been off it. We
|
||||||
* it. We just fall through and let the index AM do the work.
|
* just fall through and let the index AM do the work. Note we
|
||||||
* Note we should get the right answer regardless of scan
|
* should get the right answer regardless of scan direction.
|
||||||
* direction.
|
|
||||||
*/
|
*/
|
||||||
scan->unique_tuple_pos = 0; /* need to update position */
|
scan->unique_tuple_pos = 0; /* need to update position */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Moving off the tuple; must do amrescan to release
|
* Moving off the tuple; must do amrescan to release index-level
|
||||||
* index-level pins before we return NULL. Since index_rescan
|
* pins before we return NULL. Since index_rescan will reset my
|
||||||
* will reset my state, must save and restore...
|
* state, must save and restore...
|
||||||
*/
|
*/
|
||||||
int unique_tuple_mark = scan->unique_tuple_mark;
|
int unique_tuple_mark = scan->unique_tuple_mark;
|
||||||
|
|
||||||
|
@ -520,8 +519,7 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
||||||
bool found;
|
bool found;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The AM's gettuple proc finds the next tuple matching the scan
|
* The AM's gettuple proc finds the next tuple matching the scan keys.
|
||||||
* keys.
|
|
||||||
*/
|
*/
|
||||||
found = DatumGetBool(FunctionCall2(procedure,
|
found = DatumGetBool(FunctionCall2(procedure,
|
||||||
PointerGetDatum(scan),
|
PointerGetDatum(scan),
|
||||||
|
@ -556,9 +554,9 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we can't see it, maybe no one else can either. Check to see
|
* If we can't see it, maybe no one else can either. Check to see if
|
||||||
* if the tuple is dead to all transactions. If so, signal the
|
* the tuple is dead to all transactions. If so, signal the index AM
|
||||||
* index AM to not return it on future indexscans.
|
* to not return it on future indexscans.
|
||||||
*
|
*
|
||||||
* We told heap_release_fetch to keep a pin on the buffer, so we can
|
* We told heap_release_fetch to keep a pin on the buffer, so we can
|
||||||
* re-access the tuple here. But we must re-lock the buffer first.
|
* re-access the tuple here. But we must re-lock the buffer first.
|
||||||
|
@ -576,8 +574,8 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
|
||||||
scan->got_tuple = true;
|
scan->got_tuple = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we just fetched a known-unique tuple, then subsequent calls will
|
* If we just fetched a known-unique tuple, then subsequent calls will go
|
||||||
* go through the short-circuit code above. unique_tuple_pos has been
|
* through the short-circuit code above. unique_tuple_pos has been
|
||||||
* initialized to 0, which is the correct state ("on row").
|
* initialized to 0, which is the correct state ("on row").
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -805,11 +803,10 @@ index_getprocinfo(Relation irel,
|
||||||
procId = loc[procindex];
|
procId = loc[procindex];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Complain if function was not found during
|
* Complain if function was not found during IndexSupportInitialize.
|
||||||
* IndexSupportInitialize. This should not happen unless the
|
* This should not happen unless the system tables contain bogus
|
||||||
* system tables contain bogus entries for the index opclass. (If
|
* entries for the index opclass. (If an AM wants to allow a support
|
||||||
* an AM wants to allow a support function to be optional, it can
|
* function to be optional, it can use index_getprocid.)
|
||||||
* use index_getprocid.)
|
|
||||||
*/
|
*/
|
||||||
if (!RegProcedureIsValid(procId))
|
if (!RegProcedureIsValid(procId))
|
||||||
elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
|
elog(ERROR, "missing support function %d for attribute %d of index \"%s\"",
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.126 2005/10/12 17:18:03 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtinsert.c,v 1.127 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -93,30 +93,29 @@ top:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the page was split between the time that we surrendered our read
|
* If the page was split between the time that we surrendered our read
|
||||||
* lock and acquired our write lock, then this page may no longer be
|
* lock and acquired our write lock, then this page may no longer be the
|
||||||
* the right place for the key we want to insert. In this case, we
|
* right place for the key we want to insert. In this case, we need to
|
||||||
* need to move right in the tree. See Lehman and Yao for an
|
* move right in the tree. See Lehman and Yao for an excruciatingly
|
||||||
* excruciatingly precise description.
|
* precise description.
|
||||||
*/
|
*/
|
||||||
buf = _bt_moveright(rel, buf, natts, itup_scankey, false, BT_WRITE);
|
buf = _bt_moveright(rel, buf, natts, itup_scankey, false, BT_WRITE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we're not allowing duplicates, make sure the key isn't already
|
* If we're not allowing duplicates, make sure the key isn't already in
|
||||||
* in the index.
|
* the index.
|
||||||
*
|
*
|
||||||
* NOTE: obviously, _bt_check_unique can only detect keys that are
|
* NOTE: obviously, _bt_check_unique can only detect keys that are already in
|
||||||
* already in the index; so it cannot defend against concurrent
|
* the index; so it cannot defend against concurrent insertions of the
|
||||||
* insertions of the same key. We protect against that by means of
|
* same key. We protect against that by means of holding a write lock on
|
||||||
* holding a write lock on the target page. Any other would-be
|
* the target page. Any other would-be inserter of the same key must
|
||||||
* inserter of the same key must acquire a write lock on the same
|
* acquire a write lock on the same target page, so only one would-be
|
||||||
* target page, so only one would-be inserter can be making the check
|
* inserter can be making the check at one time. Furthermore, once we are
|
||||||
* at one time. Furthermore, once we are past the check we hold write
|
* past the check we hold write locks continuously until we have performed
|
||||||
* locks continuously until we have performed our insertion, so no
|
* our insertion, so no later inserter can fail to see our insertion.
|
||||||
* later inserter can fail to see our insertion. (This requires some
|
* (This requires some care in _bt_insertonpg.)
|
||||||
* care in _bt_insertonpg.)
|
|
||||||
*
|
*
|
||||||
* If we must wait for another xact, we release the lock while waiting,
|
* If we must wait for another xact, we release the lock while waiting, and
|
||||||
* and then must start over completely.
|
* then must start over completely.
|
||||||
*/
|
*/
|
||||||
if (index_is_unique)
|
if (index_is_unique)
|
||||||
{
|
{
|
||||||
|
@ -167,8 +166,8 @@ _bt_check_unique(Relation rel, BTItem btitem, Relation heapRel,
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find first item >= proposed new item. Note we could also get a
|
* Find first item >= proposed new item. Note we could also get a pointer
|
||||||
* pointer to end-of-page here.
|
* to end-of-page here.
|
||||||
*/
|
*/
|
||||||
offset = _bt_binsrch(rel, buf, natts, itup_scankey, false);
|
offset = _bt_binsrch(rel, buf, natts, itup_scankey, false);
|
||||||
|
|
||||||
|
@ -194,24 +193,24 @@ _bt_check_unique(Relation rel, BTItem btitem, Relation heapRel,
|
||||||
/*
|
/*
|
||||||
* We can skip items that are marked killed.
|
* We can skip items that are marked killed.
|
||||||
*
|
*
|
||||||
* Formerly, we applied _bt_isequal() before checking the kill
|
* Formerly, we applied _bt_isequal() before checking the kill flag,
|
||||||
* flag, so as to fall out of the item loop as soon as
|
* so as to fall out of the item loop as soon as possible.
|
||||||
* possible. However, in the presence of heavy update activity
|
* However, in the presence of heavy update activity an index may
|
||||||
* an index may contain many killed items with the same key;
|
* contain many killed items with the same key; running
|
||||||
* running _bt_isequal() on each killed item gets expensive.
|
* _bt_isequal() on each killed item gets expensive. Furthermore
|
||||||
* Furthermore it is likely that the non-killed version of
|
* it is likely that the non-killed version of each key appears
|
||||||
* each key appears first, so that we didn't actually get to
|
* first, so that we didn't actually get to exit any sooner
|
||||||
* exit any sooner anyway. So now we just advance over killed
|
* anyway. So now we just advance over killed items as quickly as
|
||||||
* items as quickly as we can. We only apply _bt_isequal()
|
* we can. We only apply _bt_isequal() when we get to a non-killed
|
||||||
* when we get to a non-killed item or the end of the page.
|
* item or the end of the page.
|
||||||
*/
|
*/
|
||||||
if (!ItemIdDeleted(curitemid))
|
if (!ItemIdDeleted(curitemid))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* _bt_compare returns 0 for (1,NULL) and (1,NULL) -
|
* _bt_compare returns 0 for (1,NULL) and (1,NULL) - this's
|
||||||
* this's how we handling NULLs - and so we must not use
|
* how we handling NULLs - and so we must not use _bt_compare
|
||||||
* _bt_compare in real comparison, but only for
|
* in real comparison, but only for ordering/finding items on
|
||||||
* ordering/finding items on pages. - vadim 03/24/97
|
* pages. - vadim 03/24/97
|
||||||
*/
|
*/
|
||||||
if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
|
if (!_bt_isequal(itupdesc, page, offset, natts, itup_scankey))
|
||||||
break; /* we're past all the equal tuples */
|
break; /* we're past all the equal tuples */
|
||||||
|
@ -252,9 +251,9 @@ _bt_check_unique(Relation rel, BTItem btitem, Relation heapRel,
|
||||||
else if (htup.t_data != NULL)
|
else if (htup.t_data != NULL)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Hmm, if we can't see the tuple, maybe it can be
|
* Hmm, if we can't see the tuple, maybe it can be marked
|
||||||
* marked killed. This logic should match
|
* killed. This logic should match index_getnext and
|
||||||
* index_getnext and btgettuple.
|
* btgettuple.
|
||||||
*/
|
*/
|
||||||
LockBuffer(hbuffer, BUFFER_LOCK_SHARE);
|
LockBuffer(hbuffer, BUFFER_LOCK_SHARE);
|
||||||
if (HeapTupleSatisfiesVacuum(htup.t_data, RecentGlobalXmin,
|
if (HeapTupleSatisfiesVacuum(htup.t_data, RecentGlobalXmin,
|
||||||
|
@ -377,15 +376,15 @@ _bt_insertonpg(Relation rel,
|
||||||
itemsz = IndexTupleDSize(btitem->bti_itup)
|
itemsz = IndexTupleDSize(btitem->bti_itup)
|
||||||
+ (sizeof(BTItemData) - sizeof(IndexTupleData));
|
+ (sizeof(BTItemData) - sizeof(IndexTupleData));
|
||||||
|
|
||||||
itemsz = MAXALIGN(itemsz); /* be safe, PageAddItem will do this but
|
itemsz = MAXALIGN(itemsz); /* be safe, PageAddItem will do this but we
|
||||||
* we need to be consistent */
|
* need to be consistent */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the item can fit on a btree page at all. (Eventually,
|
* Check whether the item can fit on a btree page at all. (Eventually, we
|
||||||
* we ought to try to apply TOAST methods if not.) We actually need to
|
* ought to try to apply TOAST methods if not.) We actually need to be
|
||||||
* be able to fit three items on every page, so restrict any one item
|
* able to fit three items on every page, so restrict any one item to 1/3
|
||||||
* to 1/3 the per-page available space. Note that at this point,
|
* the per-page available space. Note that at this point, itemsz doesn't
|
||||||
* itemsz doesn't include the ItemId.
|
* include the ItemId.
|
||||||
*/
|
*/
|
||||||
if (itemsz > BTMaxItemSize(page))
|
if (itemsz > BTMaxItemSize(page))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -432,11 +431,11 @@ _bt_insertonpg(Relation rel,
|
||||||
/*
|
/*
|
||||||
* step right to next non-dead page
|
* step right to next non-dead page
|
||||||
*
|
*
|
||||||
* must write-lock that page before releasing write lock on
|
* must write-lock that page before releasing write lock on current
|
||||||
* current page; else someone else's _bt_check_unique scan
|
* page; else someone else's _bt_check_unique scan could fail to
|
||||||
* could fail to see our insertion. write locks on
|
* see our insertion. write locks on intermediate dead pages
|
||||||
* intermediate dead pages won't do because we don't know when
|
* won't do because we don't know when they will get de-linked
|
||||||
* they will get de-linked from the tree.
|
* from the tree.
|
||||||
*/
|
*/
|
||||||
Buffer rbuf = InvalidBuffer;
|
Buffer rbuf = InvalidBuffer;
|
||||||
|
|
||||||
|
@ -459,9 +458,9 @@ _bt_insertonpg(Relation rel,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now we are on the right page, so find the insert position. If
|
* Now we are on the right page, so find the insert position. If we
|
||||||
* we moved right at all, we know we should insert at the start of
|
* moved right at all, we know we should insert at the start of the
|
||||||
* the page, else must find the position by searching.
|
* page, else must find the position by searching.
|
||||||
*/
|
*/
|
||||||
if (movedright)
|
if (movedright)
|
||||||
newitemoff = P_FIRSTDATAKEY(lpageop);
|
newitemoff = P_FIRSTDATAKEY(lpageop);
|
||||||
|
@ -472,9 +471,9 @@ _bt_insertonpg(Relation rel,
|
||||||
/*
|
/*
|
||||||
* Do we need to split the page to fit the item on it?
|
* Do we need to split the page to fit the item on it?
|
||||||
*
|
*
|
||||||
* Note: PageGetFreeSpace() subtracts sizeof(ItemIdData) from its result,
|
* Note: PageGetFreeSpace() subtracts sizeof(ItemIdData) from its result, so
|
||||||
* so this comparison is correct even though we appear to be
|
* this comparison is correct even though we appear to be accounting only
|
||||||
* accounting only for the item and not for its line pointer.
|
* for the item and not for its line pointer.
|
||||||
*/
|
*/
|
||||||
if (PageGetFreeSpace(page) < itemsz)
|
if (PageGetFreeSpace(page) < itemsz)
|
||||||
{
|
{
|
||||||
|
@ -522,12 +521,11 @@ _bt_insertonpg(Relation rel,
|
||||||
itup_blkno = BufferGetBlockNumber(buf);
|
itup_blkno = BufferGetBlockNumber(buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are doing this insert because we split a page that was
|
* If we are doing this insert because we split a page that was the
|
||||||
* the only one on its tree level, but was not the root, it may
|
* only one on its tree level, but was not the root, it may have been
|
||||||
* have been the "fast root". We need to ensure that the fast
|
* the "fast root". We need to ensure that the fast root link points
|
||||||
* root link points at or above the current page. We can safely
|
* at or above the current page. We can safely acquire a lock on the
|
||||||
* acquire a lock on the metapage here --- see comments for
|
* metapage here --- see comments for _bt_newroot().
|
||||||
* _bt_newroot().
|
|
||||||
*/
|
*/
|
||||||
if (split_only_page)
|
if (split_only_page)
|
||||||
{
|
{
|
||||||
|
@ -692,11 +690,11 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||||
lopaque->btpo.level = ropaque->btpo.level = oopaque->btpo.level;
|
lopaque->btpo.level = ropaque->btpo.level = oopaque->btpo.level;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the page we're splitting is not the rightmost page at its level
|
* If the page we're splitting is not the rightmost page at its level in
|
||||||
* in the tree, then the first entry on the page is the high key for
|
* the tree, then the first entry on the page is the high key for the
|
||||||
* the page. We need to copy that to the right half. Otherwise
|
* page. We need to copy that to the right half. Otherwise (meaning the
|
||||||
* (meaning the rightmost page case), all the items on the right half
|
* rightmost page case), all the items on the right half will be user
|
||||||
* will be user data.
|
* data.
|
||||||
*/
|
*/
|
||||||
rightoff = P_HIKEY;
|
rightoff = P_HIKEY;
|
||||||
|
|
||||||
|
@ -712,9 +710,9 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The "high key" for the new left page will be the first key that's
|
* The "high key" for the new left page will be the first key that's going
|
||||||
* going to go into the new right page. This might be either the
|
* to go into the new right page. This might be either the existing data
|
||||||
* existing data item at position firstright, or the incoming tuple.
|
* item at position firstright, or the incoming tuple.
|
||||||
*/
|
*/
|
||||||
leftoff = P_HIKEY;
|
leftoff = P_HIKEY;
|
||||||
if (!newitemonleft && newitemoff == firstright)
|
if (!newitemonleft && newitemoff == firstright)
|
||||||
|
@ -806,8 +804,8 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||||
/*
|
/*
|
||||||
* We have to grab the right sibling (if any) and fix the prev pointer
|
* We have to grab the right sibling (if any) and fix the prev pointer
|
||||||
* there. We are guaranteed that this is deadlock-free since no other
|
* there. We are guaranteed that this is deadlock-free since no other
|
||||||
* writer will be holding a lock on that page and trying to move left,
|
* writer will be holding a lock on that page and trying to move left, and
|
||||||
* and all readers release locks on a page before trying to fetch its
|
* all readers release locks on a page before trying to fetch its
|
||||||
* neighbors.
|
* neighbors.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -821,8 +819,8 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Right sibling is locked, new siblings are prepared, but original
|
* Right sibling is locked, new siblings are prepared, but original page
|
||||||
* page is not updated yet. Log changes before continuing.
|
* is not updated yet. Log changes before continuing.
|
||||||
*
|
*
|
||||||
* NO EREPORT(ERROR) till right sibling is updated.
|
* NO EREPORT(ERROR) till right sibling is updated.
|
||||||
*/
|
*/
|
||||||
|
@ -850,10 +848,10 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||||
xlrec.level = lopaque->btpo.level;
|
xlrec.level = lopaque->btpo.level;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Direct access to page is not good but faster - we should
|
* Direct access to page is not good but faster - we should implement
|
||||||
* implement some new func in page API. Note we only store the
|
* some new func in page API. Note we only store the tuples
|
||||||
* tuples themselves, knowing that the item pointers are in the
|
* themselves, knowing that the item pointers are in the same order
|
||||||
* same order and can be reconstructed by scanning the tuples.
|
* and can be reconstructed by scanning the tuples.
|
||||||
*/
|
*/
|
||||||
xlrec.leftlen = ((PageHeader) leftpage)->pd_special -
|
xlrec.leftlen = ((PageHeader) leftpage)->pd_special -
|
||||||
((PageHeader) leftpage)->pd_upper;
|
((PageHeader) leftpage)->pd_upper;
|
||||||
|
@ -903,13 +901,13 @@ _bt_split(Relation rel, Buffer buf, OffsetNumber firstright,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By here, the original data page has been split into two new halves,
|
* By here, the original data page has been split into two new halves, and
|
||||||
* and these are correct. The algorithm requires that the left page
|
* these are correct. The algorithm requires that the left page never
|
||||||
* never move during a split, so we copy the new left page back on top
|
* move during a split, so we copy the new left page back on top of the
|
||||||
* of the original. Note that this is not a waste of time, since we
|
* original. Note that this is not a waste of time, since we also require
|
||||||
* also require (in the page management code) that the center of a
|
* (in the page management code) that the center of a page always be
|
||||||
* page always be clean, and the most efficient way to guarantee this
|
* clean, and the most efficient way to guarantee this is just to compact
|
||||||
* is just to compact the data by reinserting it into a new left page.
|
* the data by reinserting it into a new left page.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
PageRestoreTempPage(leftpage, origpage);
|
PageRestoreTempPage(leftpage, origpage);
|
||||||
|
@ -984,13 +982,13 @@ _bt_findsplitloc(Relation rel,
|
||||||
MAXALIGN(sizeof(BTPageOpaqueData));
|
MAXALIGN(sizeof(BTPageOpaqueData));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finding the best possible split would require checking all the
|
* Finding the best possible split would require checking all the possible
|
||||||
* possible split points, because of the high-key and left-key special
|
* split points, because of the high-key and left-key special cases.
|
||||||
* cases. That's probably more work than it's worth; instead, stop as
|
* That's probably more work than it's worth; instead, stop as soon as we
|
||||||
* soon as we find a "good-enough" split, where good-enough is defined
|
* find a "good-enough" split, where good-enough is defined as an
|
||||||
* as an imbalance in free space of no more than pagesize/16
|
* imbalance in free space of no more than pagesize/16 (arbitrary...) This
|
||||||
* (arbitrary...) This should let us stop near the middle on most
|
* should let us stop near the middle on most pages, instead of plowing to
|
||||||
* pages, instead of plowing to the end.
|
* the end.
|
||||||
*/
|
*/
|
||||||
goodenough = leftspace / 16;
|
goodenough = leftspace / 16;
|
||||||
|
|
||||||
|
@ -1006,8 +1004,8 @@ _bt_findsplitloc(Relation rel,
|
||||||
dataitemtotal = rightspace - (int) PageGetFreeSpace(page);
|
dataitemtotal = rightspace - (int) PageGetFreeSpace(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan through the data items and calculate space usage for a split
|
* Scan through the data items and calculate space usage for a split at
|
||||||
* at each possible position.
|
* each possible position.
|
||||||
*/
|
*/
|
||||||
dataitemstoleft = 0;
|
dataitemstoleft = 0;
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
@ -1024,9 +1022,9 @@ _bt_findsplitloc(Relation rel,
|
||||||
itemsz = MAXALIGN(ItemIdGetLength(itemid)) + sizeof(ItemIdData);
|
itemsz = MAXALIGN(ItemIdGetLength(itemid)) + sizeof(ItemIdData);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to allow for the current item becoming the high key of
|
* We have to allow for the current item becoming the high key of the
|
||||||
* the left page; therefore it counts against left space as well
|
* left page; therefore it counts against left space as well as right
|
||||||
* as right space.
|
* space.
|
||||||
*/
|
*/
|
||||||
leftfree = leftspace - dataitemstoleft - (int) itemsz;
|
leftfree = leftspace - dataitemstoleft - (int) itemsz;
|
||||||
rightfree = rightspace - (dataitemtotal - dataitemstoleft);
|
rightfree = rightspace - (dataitemtotal - dataitemstoleft);
|
||||||
|
@ -1058,8 +1056,8 @@ _bt_findsplitloc(Relation rel,
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* I believe it is not possible to fail to find a feasible split, but
|
* I believe it is not possible to fail to find a feasible split, but just
|
||||||
* just in case ...
|
* in case ...
|
||||||
*/
|
*/
|
||||||
if (!state.have_split)
|
if (!state.have_split)
|
||||||
elog(ERROR, "could not find a feasible split point for \"%s\"",
|
elog(ERROR, "could not find a feasible split point for \"%s\"",
|
||||||
|
@ -1105,8 +1103,7 @@ _bt_checksplitloc(FindSplitData *state, OffsetNumber firstright,
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* On a rightmost page, try to equalize right free space with
|
* On a rightmost page, try to equalize right free space with
|
||||||
* twice the left free space. See comments for
|
* twice the left free space. See comments for _bt_findsplitloc.
|
||||||
* _bt_findsplitloc.
|
|
||||||
*/
|
*/
|
||||||
delta = (2 * leftfree) - rightfree;
|
delta = (2 * leftfree) - rightfree;
|
||||||
}
|
}
|
||||||
|
@ -1153,19 +1150,18 @@ _bt_insert_parent(Relation rel,
|
||||||
bool is_only)
|
bool is_only)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Here we have to do something Lehman and Yao don't talk about: deal
|
* Here we have to do something Lehman and Yao don't talk about: deal with
|
||||||
* with a root split and construction of a new root. If our stack is
|
* a root split and construction of a new root. If our stack is empty
|
||||||
* empty then we have just split a node on what had been the root
|
* then we have just split a node on what had been the root level when we
|
||||||
* level when we descended the tree. If it was still the root then we
|
* descended the tree. If it was still the root then we perform a
|
||||||
* perform a new-root construction. If it *wasn't* the root anymore,
|
* new-root construction. If it *wasn't* the root anymore, search to find
|
||||||
* search to find the next higher level that someone constructed
|
* the next higher level that someone constructed meanwhile, and find the
|
||||||
* meanwhile, and find the right place to insert as for the normal
|
* right place to insert as for the normal case.
|
||||||
* case.
|
|
||||||
*
|
*
|
||||||
* If we have to search for the parent level, we do so by re-descending
|
* If we have to search for the parent level, we do so by re-descending from
|
||||||
* from the root. This is not super-efficient, but it's rare enough
|
* the root. This is not super-efficient, but it's rare enough not to
|
||||||
* not to matter. (This path is also taken when called from WAL
|
* matter. (This path is also taken when called from WAL recovery --- we
|
||||||
* recovery --- we have no stack in that case.)
|
* have no stack in that case.)
|
||||||
*/
|
*/
|
||||||
if (is_root)
|
if (is_root)
|
||||||
{
|
{
|
||||||
|
@ -1219,9 +1215,9 @@ _bt_insert_parent(Relation rel,
|
||||||
/*
|
/*
|
||||||
* Find the parent buffer and get the parent page.
|
* Find the parent buffer and get the parent page.
|
||||||
*
|
*
|
||||||
* Oops - if we were moved right then we need to change stack item!
|
* Oops - if we were moved right then we need to change stack item! We
|
||||||
* We want to find parent pointing to where we are, right ? -
|
* want to find parent pointing to where we are, right ? - vadim
|
||||||
* vadim 05/27/97
|
* 05/27/97
|
||||||
*/
|
*/
|
||||||
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
||||||
bknum, P_HIKEY);
|
bknum, P_HIKEY);
|
||||||
|
@ -1291,9 +1287,9 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* start = InvalidOffsetNumber means "search the whole page".
|
* start = InvalidOffsetNumber means "search the whole page". We
|
||||||
* We need this test anyway due to possibility that page has a
|
* need this test anyway due to possibility that page has a high
|
||||||
* high key now when it didn't before.
|
* key now when it didn't before.
|
||||||
*/
|
*/
|
||||||
if (start < minoff)
|
if (start < minoff)
|
||||||
start = minoff;
|
start = minoff;
|
||||||
|
@ -1307,8 +1303,8 @@ _bt_getstackbuf(Relation rel, BTStack stack, int access)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* These loops will check every item on the page --- but in an
|
* These loops will check every item on the page --- but in an
|
||||||
* order that's attuned to the probability of where it
|
* order that's attuned to the probability of where it actually
|
||||||
* actually is. Scan to the right first, then to the left.
|
* is. Scan to the right first, then to the left.
|
||||||
*/
|
*/
|
||||||
for (offnum = start;
|
for (offnum = start;
|
||||||
offnum <= maxoff;
|
offnum <= maxoff;
|
||||||
|
@ -1424,9 +1420,9 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
|
||||||
metad->btm_fastlevel = rootopaque->btpo.level;
|
metad->btm_fastlevel = rootopaque->btpo.level;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create downlink item for left page (old root). Since this will be
|
* Create downlink item for left page (old root). Since this will be the
|
||||||
* the first item in a non-leaf page, it implicitly has minus-infinity
|
* first item in a non-leaf page, it implicitly has minus-infinity key
|
||||||
* key value, so we need not store any actual key in it.
|
* value, so we need not store any actual key in it.
|
||||||
*/
|
*/
|
||||||
itemsz = sizeof(BTItemData);
|
itemsz = sizeof(BTItemData);
|
||||||
new_item = (BTItem) palloc(itemsz);
|
new_item = (BTItem) palloc(itemsz);
|
||||||
|
@ -1434,17 +1430,17 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
|
||||||
ItemPointerSet(&(new_item->bti_itup.t_tid), lbkno, P_HIKEY);
|
ItemPointerSet(&(new_item->bti_itup.t_tid), lbkno, P_HIKEY);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Insert the left page pointer into the new root page. The root page
|
* Insert the left page pointer into the new root page. The root page is
|
||||||
* is the rightmost page on its level so there is no "high key" in it;
|
* the rightmost page on its level so there is no "high key" in it; the
|
||||||
* the two items will go into positions P_HIKEY and P_FIRSTKEY.
|
* two items will go into positions P_HIKEY and P_FIRSTKEY.
|
||||||
*/
|
*/
|
||||||
if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
|
if (PageAddItem(rootpage, (Item) new_item, itemsz, P_HIKEY, LP_USED) == InvalidOffsetNumber)
|
||||||
elog(PANIC, "failed to add leftkey to new root page");
|
elog(PANIC, "failed to add leftkey to new root page");
|
||||||
pfree(new_item);
|
pfree(new_item);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create downlink item for right page. The key for it is obtained
|
* Create downlink item for right page. The key for it is obtained from
|
||||||
* from the "high key" position in the left page.
|
* the "high key" position in the left page.
|
||||||
*/
|
*/
|
||||||
itemid = PageGetItemId(lpage, P_HIKEY);
|
itemid = PageGetItemId(lpage, P_HIKEY);
|
||||||
itemsz = ItemIdGetLength(itemid);
|
itemsz = ItemIdGetLength(itemid);
|
||||||
|
@ -1476,8 +1472,8 @@ _bt_newroot(Relation rel, Buffer lbuf, Buffer rbuf)
|
||||||
rdata[0].next = &(rdata[1]);
|
rdata[0].next = &(rdata[1]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Direct access to page is not good but faster - we should
|
* Direct access to page is not good but faster - we should implement
|
||||||
* implement some new func in page API.
|
* some new func in page API.
|
||||||
*/
|
*/
|
||||||
rdata[1].data = (char *) rootpage + ((PageHeader) rootpage)->pd_upper;
|
rdata[1].data = (char *) rootpage + ((PageHeader) rootpage)->pd_upper;
|
||||||
rdata[1].len = ((PageHeader) rootpage)->pd_special -
|
rdata[1].len = ((PageHeader) rootpage)->pd_special -
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.87 2005/08/12 14:34:14 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtpage.c,v 1.88 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* Postgres btree pages look like ordinary relation pages. The opaque
|
* Postgres btree pages look like ordinary relation pages. The opaque
|
||||||
|
@ -115,8 +115,8 @@ _bt_initmetapage(Page page, BlockNumber rootbknum, uint32 level)
|
||||||
metaopaque->btpo_flags = BTP_META;
|
metaopaque->btpo_flags = BTP_META;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set pd_lower just past the end of the metadata. This is not
|
* Set pd_lower just past the end of the metadata. This is not essential
|
||||||
* essential but it makes the page look compressible to xlog.c.
|
* but it makes the page look compressible to xlog.c.
|
||||||
*/
|
*/
|
||||||
((PageHeader) page)->pd_lower =
|
((PageHeader) page)->pd_lower =
|
||||||
((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
|
((char *) metad + sizeof(BTMetaPageData)) - (char *) page;
|
||||||
|
@ -198,26 +198,26 @@ _bt_getroot(Relation rel, int access)
|
||||||
LockBuffer(metabuf, BT_WRITE);
|
LockBuffer(metabuf, BT_WRITE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Race condition: if someone else initialized the metadata
|
* Race condition: if someone else initialized the metadata between
|
||||||
* between the time we released the read lock and acquired the
|
* the time we released the read lock and acquired the write lock, we
|
||||||
* write lock, we must avoid doing it again.
|
* must avoid doing it again.
|
||||||
*/
|
*/
|
||||||
if (metad->btm_root != P_NONE)
|
if (metad->btm_root != P_NONE)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Metadata initialized by someone else. In order to
|
* Metadata initialized by someone else. In order to guarantee no
|
||||||
* guarantee no deadlocks, we have to release the metadata
|
* deadlocks, we have to release the metadata page and start all
|
||||||
* page and start all over again. (Is that really true? But
|
* over again. (Is that really true? But it's hardly worth trying
|
||||||
* it's hardly worth trying to optimize this case.)
|
* to optimize this case.)
|
||||||
*/
|
*/
|
||||||
_bt_relbuf(rel, metabuf);
|
_bt_relbuf(rel, metabuf);
|
||||||
return _bt_getroot(rel, access);
|
return _bt_getroot(rel, access);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get, initialize, write, and leave a lock of the appropriate
|
* Get, initialize, write, and leave a lock of the appropriate type on
|
||||||
* type on the new root page. Since this is the first page in the
|
* the new root page. Since this is the first page in the tree, it's
|
||||||
* tree, it's a leaf as well as the root.
|
* a leaf as well as the root.
|
||||||
*/
|
*/
|
||||||
rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
|
rootbuf = _bt_getbuf(rel, P_NEW, BT_WRITE);
|
||||||
rootblkno = BufferGetBlockNumber(rootbuf);
|
rootblkno = BufferGetBlockNumber(rootbuf);
|
||||||
|
@ -266,9 +266,9 @@ _bt_getroot(Relation rel, int access)
|
||||||
_bt_wrtnorelbuf(rel, rootbuf);
|
_bt_wrtnorelbuf(rel, rootbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* swap root write lock for read lock. There is no danger of
|
* swap root write lock for read lock. There is no danger of anyone
|
||||||
* anyone else accessing the new root page while it's unlocked,
|
* else accessing the new root page while it's unlocked, since no one
|
||||||
* since no one else knows where it is yet.
|
* else knows where it is yet.
|
||||||
*/
|
*/
|
||||||
LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);
|
LockBuffer(rootbuf, BUFFER_LOCK_UNLOCK);
|
||||||
LockBuffer(rootbuf, BT_READ);
|
LockBuffer(rootbuf, BT_READ);
|
||||||
|
@ -312,8 +312,8 @@ _bt_getroot(Relation rel, int access)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* By here, we have a pin and read lock on the root page, and no lock
|
* By here, we have a pin and read lock on the root page, and no lock set
|
||||||
* set on the metadata page. Return the root page's buffer.
|
* on the metadata page. Return the root page's buffer.
|
||||||
*/
|
*/
|
||||||
return rootbuf;
|
return rootbuf;
|
||||||
}
|
}
|
||||||
|
@ -435,27 +435,26 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
||||||
/*
|
/*
|
||||||
* First see if the FSM knows of any free pages.
|
* First see if the FSM knows of any free pages.
|
||||||
*
|
*
|
||||||
* We can't trust the FSM's report unreservedly; we have to check
|
* We can't trust the FSM's report unreservedly; we have to check that
|
||||||
* that the page is still free. (For example, an already-free
|
* the page is still free. (For example, an already-free page could
|
||||||
* page could have been re-used between the time the last VACUUM
|
* have been re-used between the time the last VACUUM scanned it and
|
||||||
* scanned it and the time the VACUUM made its FSM updates.)
|
* the time the VACUUM made its FSM updates.)
|
||||||
*
|
*
|
||||||
* In fact, it's worse than that: we can't even assume that it's safe
|
* In fact, it's worse than that: we can't even assume that it's safe to
|
||||||
* to take a lock on the reported page. If somebody else has a
|
* take a lock on the reported page. If somebody else has a lock on
|
||||||
* lock on it, or even worse our own caller does, we could
|
* it, or even worse our own caller does, we could deadlock. (The
|
||||||
* deadlock. (The own-caller scenario is actually not improbable.
|
* own-caller scenario is actually not improbable. Consider an index
|
||||||
* Consider an index on a serial or timestamp column. Nearly all
|
* on a serial or timestamp column. Nearly all splits will be at the
|
||||||
* splits will be at the rightmost page, so it's entirely likely
|
* rightmost page, so it's entirely likely that _bt_split will call us
|
||||||
* that _bt_split will call us while holding a lock on the page
|
* while holding a lock on the page most recently acquired from FSM.
|
||||||
* most recently acquired from FSM. A VACUUM running concurrently
|
* A VACUUM running concurrently with the previous split could well
|
||||||
* with the previous split could well have placed that page back
|
* have placed that page back in FSM.)
|
||||||
* in FSM.)
|
|
||||||
*
|
*
|
||||||
* To get around that, we ask for only a conditional lock on the
|
* To get around that, we ask for only a conditional lock on the reported
|
||||||
* reported page. If we fail, then someone else is using the
|
* page. If we fail, then someone else is using the page, and we may
|
||||||
* page, and we may reasonably assume it's not free. (If we
|
* reasonably assume it's not free. (If we happen to be wrong, the
|
||||||
* happen to be wrong, the worst consequence is the page will be
|
* worst consequence is the page will be lost to use till the next
|
||||||
* lost to use till the next VACUUM, which is no big problem.)
|
* VACUUM, which is no big problem.)
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -486,10 +485,10 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
||||||
/*
|
/*
|
||||||
* Extend the relation by one page.
|
* Extend the relation by one page.
|
||||||
*
|
*
|
||||||
* We have to use a lock to ensure no one else is extending the rel
|
* We have to use a lock to ensure no one else is extending the rel at
|
||||||
* at the same time, else we will both try to initialize the same
|
* the same time, else we will both try to initialize the same new
|
||||||
* new page. We can skip locking for new or temp relations,
|
* page. We can skip locking for new or temp relations, however,
|
||||||
* however, since no one else could be accessing them.
|
* since no one else could be accessing them.
|
||||||
*/
|
*/
|
||||||
needLock = !RELATION_IS_LOCAL(rel);
|
needLock = !RELATION_IS_LOCAL(rel);
|
||||||
|
|
||||||
|
@ -504,8 +503,8 @@ _bt_getbuf(Relation rel, BlockNumber blkno, int access)
|
||||||
/*
|
/*
|
||||||
* Release the file-extension lock; it's now OK for someone else to
|
* Release the file-extension lock; it's now OK for someone else to
|
||||||
* extend the relation some more. Note that we cannot release this
|
* extend the relation some more. Note that we cannot release this
|
||||||
* lock before we have buffer lock on the new page, or we risk a
|
* lock before we have buffer lock on the new page, or we risk a race
|
||||||
* race condition against btvacuumcleanup --- see comments therein.
|
* condition against btvacuumcleanup --- see comments therein.
|
||||||
*/
|
*/
|
||||||
if (needLock)
|
if (needLock)
|
||||||
UnlockRelationForExtension(rel, ExclusiveLock);
|
UnlockRelationForExtension(rel, ExclusiveLock);
|
||||||
|
@ -614,10 +613,10 @@ _bt_page_recyclable(Page page)
|
||||||
BTPageOpaque opaque;
|
BTPageOpaque opaque;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* It's possible to find an all-zeroes page in an index --- for
|
* It's possible to find an all-zeroes page in an index --- for example, a
|
||||||
* example, a backend might successfully extend the relation one page
|
* backend might successfully extend the relation one page and then crash
|
||||||
* and then crash before it is able to make a WAL entry for adding the
|
* before it is able to make a WAL entry for adding the page. If we find a
|
||||||
* page. If we find a zeroed page then reclaim it.
|
* zeroed page then reclaim it.
|
||||||
*/
|
*/
|
||||||
if (PageIsNew(page))
|
if (PageIsNew(page))
|
||||||
return true;
|
return true;
|
||||||
|
@ -672,9 +671,9 @@ _bt_delitems(Relation rel, Buffer buf,
|
||||||
rdata[0].next = &(rdata[1]);
|
rdata[0].next = &(rdata[1]);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The target-offsets array is not in the buffer, but pretend that
|
* The target-offsets array is not in the buffer, but pretend that it
|
||||||
* it is. When XLogInsert stores the whole buffer, the offsets
|
* is. When XLogInsert stores the whole buffer, the offsets array
|
||||||
* array need not be stored too.
|
* need not be stored too.
|
||||||
*/
|
*/
|
||||||
if (nitems > 0)
|
if (nitems > 0)
|
||||||
{
|
{
|
||||||
|
@ -747,8 +746,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
BTPageOpaque opaque;
|
BTPageOpaque opaque;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can never delete rightmost pages nor root pages. While at it,
|
* We can never delete rightmost pages nor root pages. While at it, check
|
||||||
* check that page is not already deleted and is empty.
|
* that page is not already deleted and is empty.
|
||||||
*/
|
*/
|
||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
@ -760,8 +759,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save info about page, including a copy of its high key (it must
|
* Save info about page, including a copy of its high key (it must have
|
||||||
* have one, being non-rightmost).
|
* one, being non-rightmost).
|
||||||
*/
|
*/
|
||||||
target = BufferGetBlockNumber(buf);
|
target = BufferGetBlockNumber(buf);
|
||||||
targetlevel = opaque->btpo.level;
|
targetlevel = opaque->btpo.level;
|
||||||
|
@ -770,11 +769,11 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
targetkey = CopyBTItem((BTItem) PageGetItem(page, itemid));
|
targetkey = CopyBTItem((BTItem) PageGetItem(page, itemid));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to get an approximate pointer to the page's parent page.
|
* We need to get an approximate pointer to the page's parent page. Use
|
||||||
* Use the standard search mechanism to search for the page's high
|
* the standard search mechanism to search for the page's high key; this
|
||||||
* key; this will give us a link to either the current parent or
|
* will give us a link to either the current parent or someplace to its
|
||||||
* someplace to its left (if there are multiple equal high keys). To
|
* left (if there are multiple equal high keys). To avoid deadlocks, we'd
|
||||||
* avoid deadlocks, we'd better drop the target page lock first.
|
* better drop the target page lock first.
|
||||||
*/
|
*/
|
||||||
_bt_relbuf(rel, buf);
|
_bt_relbuf(rel, buf);
|
||||||
/* we need a scan key to do our search, so build one */
|
/* we need a scan key to do our search, so build one */
|
||||||
|
@ -786,9 +785,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
_bt_relbuf(rel, lbuf);
|
_bt_relbuf(rel, lbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are trying to delete an interior page, _bt_search did more
|
* If we are trying to delete an interior page, _bt_search did more than
|
||||||
* than we needed. Locate the stack item pointing to our parent
|
* we needed. Locate the stack item pointing to our parent level.
|
||||||
* level.
|
|
||||||
*/
|
*/
|
||||||
ilevel = 0;
|
ilevel = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -803,16 +801,15 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We have to lock the pages we need to modify in the standard order:
|
* We have to lock the pages we need to modify in the standard order:
|
||||||
* moving right, then up. Else we will deadlock against other
|
* moving right, then up. Else we will deadlock against other writers.
|
||||||
* writers.
|
|
||||||
*
|
*
|
||||||
* So, we need to find and write-lock the current left sibling of the
|
* So, we need to find and write-lock the current left sibling of the target
|
||||||
* target page. The sibling that was current a moment ago could have
|
* page. The sibling that was current a moment ago could have split, so
|
||||||
* split, so we may have to move right. This search could fail if
|
* we may have to move right. This search could fail if either the
|
||||||
* either the sibling or the target page was deleted by someone else
|
* sibling or the target page was deleted by someone else meanwhile; if
|
||||||
* meanwhile; if so, give up. (Right now, that should never happen,
|
* so, give up. (Right now, that should never happen, since page deletion
|
||||||
* since page deletion is only done in VACUUM and there shouldn't be
|
* is only done in VACUUM and there shouldn't be multiple VACUUMs
|
||||||
* multiple VACUUMs concurrently on the same table.)
|
* concurrently on the same table.)
|
||||||
*/
|
*/
|
||||||
if (leftsib != P_NONE)
|
if (leftsib != P_NONE)
|
||||||
{
|
{
|
||||||
|
@ -839,19 +836,18 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
lbuf = InvalidBuffer;
|
lbuf = InvalidBuffer;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next write-lock the target page itself. It should be okay to take
|
* Next write-lock the target page itself. It should be okay to take just
|
||||||
* just a write lock not a superexclusive lock, since no scans would
|
* a write lock not a superexclusive lock, since no scans would stop on an
|
||||||
* stop on an empty page.
|
* empty page.
|
||||||
*/
|
*/
|
||||||
buf = _bt_getbuf(rel, target, BT_WRITE);
|
buf = _bt_getbuf(rel, target, BT_WRITE);
|
||||||
page = BufferGetPage(buf);
|
page = BufferGetPage(buf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check page is still empty etc, else abandon deletion. The empty
|
* Check page is still empty etc, else abandon deletion. The empty check
|
||||||
* check is necessary since someone else might have inserted into it
|
* is necessary since someone else might have inserted into it while we
|
||||||
* while we didn't have it locked; the others are just for paranoia's
|
* didn't have it locked; the others are just for paranoia's sake.
|
||||||
* sake.
|
|
||||||
*/
|
*/
|
||||||
if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque) ||
|
if (P_RIGHTMOST(opaque) || P_ISROOT(opaque) || P_ISDELETED(opaque) ||
|
||||||
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
P_FIRSTDATAKEY(opaque) <= PageGetMaxOffsetNumber(page))
|
||||||
|
@ -872,9 +868,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
|
rbuf = _bt_getbuf(rel, rightsib, BT_WRITE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Next find and write-lock the current parent of the target page.
|
* Next find and write-lock the current parent of the target page. This is
|
||||||
* This is essentially the same as the corresponding step of
|
* essentially the same as the corresponding step of splitting.
|
||||||
* splitting.
|
|
||||||
*/
|
*/
|
||||||
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
ItemPointerSet(&(stack->bts_btitem.bti_itup.t_tid),
|
||||||
target, P_HIKEY);
|
target, P_HIKEY);
|
||||||
|
@ -887,8 +882,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the target is the rightmost child of its parent, then we can't
|
* If the target is the rightmost child of its parent, then we can't
|
||||||
* delete, unless it's also the only child --- in which case the
|
* delete, unless it's also the only child --- in which case the parent
|
||||||
* parent changes to half-dead status.
|
* changes to half-dead status.
|
||||||
*/
|
*/
|
||||||
page = BufferGetPage(pbuf);
|
page = BufferGetPage(pbuf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
@ -917,11 +912,10 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are deleting the next-to-last page on the target's level,
|
* If we are deleting the next-to-last page on the target's level, then
|
||||||
* then the rightsib is a candidate to become the new fast root. (In
|
* the rightsib is a candidate to become the new fast root. (In theory, it
|
||||||
* theory, it might be possible to push the fast root even further
|
* might be possible to push the fast root even further down, but the odds
|
||||||
* down, but the odds of doing so are slim, and the locking
|
* of doing so are slim, and the locking considerations daunting.)
|
||||||
* considerations daunting.)
|
|
||||||
*
|
*
|
||||||
* We can safely acquire a lock on the metapage here --- see comments for
|
* We can safely acquire a lock on the metapage here --- see comments for
|
||||||
* _bt_newroot().
|
* _bt_newroot().
|
||||||
|
@ -939,9 +933,9 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
metad = BTPageGetMeta(metapg);
|
metad = BTPageGetMeta(metapg);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The expected case here is btm_fastlevel == targetlevel+1;
|
* The expected case here is btm_fastlevel == targetlevel+1; if
|
||||||
* if the fastlevel is <= targetlevel, something is wrong, and
|
* the fastlevel is <= targetlevel, something is wrong, and we
|
||||||
* we choose to overwrite it to fix it.
|
* choose to overwrite it to fix it.
|
||||||
*/
|
*/
|
||||||
if (metad->btm_fastlevel > targetlevel + 1)
|
if (metad->btm_fastlevel > targetlevel + 1)
|
||||||
{
|
{
|
||||||
|
@ -961,9 +955,9 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update parent. The normal case is a tad tricky because we want to
|
* Update parent. The normal case is a tad tricky because we want to
|
||||||
* delete the target's downlink and the *following* key. Easiest way
|
* delete the target's downlink and the *following* key. Easiest way is
|
||||||
* is to copy the right sibling's downlink over the target downlink,
|
* to copy the right sibling's downlink over the target downlink, and then
|
||||||
* and then delete the following item.
|
* delete the following item.
|
||||||
*/
|
*/
|
||||||
page = BufferGetPage(pbuf);
|
page = BufferGetPage(pbuf);
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
@ -992,8 +986,8 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update siblings' side-links. Note the target page's side-links
|
* Update siblings' side-links. Note the target page's side-links will
|
||||||
* will continue to point to the siblings.
|
* continue to point to the siblings.
|
||||||
*/
|
*/
|
||||||
if (BufferIsValid(lbuf))
|
if (BufferIsValid(lbuf))
|
||||||
{
|
{
|
||||||
|
@ -1123,10 +1117,10 @@ _bt_pagedel(Relation rel, Buffer buf, bool vacuum_full)
|
||||||
_bt_wrtbuf(rel, lbuf);
|
_bt_wrtbuf(rel, lbuf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If parent became half dead, recurse to try to delete it. Otherwise,
|
* If parent became half dead, recurse to try to delete it. Otherwise, if
|
||||||
* if right sibling is empty and is now the last child of the parent,
|
* right sibling is empty and is now the last child of the parent, recurse
|
||||||
* recurse to try to delete it. (These cases cannot apply at the same
|
* to try to delete it. (These cases cannot apply at the same time,
|
||||||
* time, though the second case might itself recurse to the first.)
|
* though the second case might itself recurse to the first.)
|
||||||
*/
|
*/
|
||||||
if (parent_half_dead)
|
if (parent_half_dead)
|
||||||
{
|
{
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.131 2005/09/02 19:02:19 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtree.c,v 1.132 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -39,9 +39,9 @@ typedef struct
|
||||||
BTSpool *spool;
|
BTSpool *spool;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* spool2 is needed only when the index is an unique index. Dead
|
* spool2 is needed only when the index is an unique index. Dead tuples
|
||||||
* tuples are put into spool2 instead of spool in order to avoid
|
* are put into spool2 instead of spool in order to avoid uniqueness
|
||||||
* uniqueness check.
|
* check.
|
||||||
*/
|
*/
|
||||||
BTSpool *spool2;
|
BTSpool *spool2;
|
||||||
double indtuples;
|
double indtuples;
|
||||||
|
@ -72,10 +72,10 @@ btbuild(PG_FUNCTION_ARGS)
|
||||||
BTBuildState buildstate;
|
BTBuildState buildstate;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* bootstrap processing does something strange, so don't use
|
* bootstrap processing does something strange, so don't use sort/build
|
||||||
* sort/build for initial catalog indices. at some point i need to
|
* for initial catalog indices. at some point i need to look harder at
|
||||||
* look harder at this. (there is some kind of incremental processing
|
* this. (there is some kind of incremental processing going on there.)
|
||||||
* going on there.) -- pma 08/29/95
|
* -- pma 08/29/95
|
||||||
*/
|
*/
|
||||||
buildstate.usefast = (FastBuild && IsNormalProcessingMode());
|
buildstate.usefast = (FastBuild && IsNormalProcessingMode());
|
||||||
buildstate.isUnique = indexInfo->ii_Unique;
|
buildstate.isUnique = indexInfo->ii_Unique;
|
||||||
|
@ -91,8 +91,8 @@ btbuild(PG_FUNCTION_ARGS)
|
||||||
#endif /* BTREE_BUILD_STATS */
|
#endif /* BTREE_BUILD_STATS */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We expect to be called exactly once for any index relation. If
|
* We expect to be called exactly once for any index relation. If that's
|
||||||
* that's not the case, big trouble's what we have.
|
* not the case, big trouble's what we have.
|
||||||
*/
|
*/
|
||||||
if (RelationGetNumberOfBlocks(index) != 0)
|
if (RelationGetNumberOfBlocks(index) != 0)
|
||||||
elog(ERROR, "index \"%s\" already contains data",
|
elog(ERROR, "index \"%s\" already contains data",
|
||||||
|
@ -103,8 +103,8 @@ btbuild(PG_FUNCTION_ARGS)
|
||||||
buildstate.spool = _bt_spoolinit(index, indexInfo->ii_Unique, false);
|
buildstate.spool = _bt_spoolinit(index, indexInfo->ii_Unique, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If building a unique index, put dead tuples in a second spool
|
* If building a unique index, put dead tuples in a second spool to
|
||||||
* to keep them out of the uniqueness check.
|
* keep them out of the uniqueness check.
|
||||||
*/
|
*/
|
||||||
if (indexInfo->ii_Unique)
|
if (indexInfo->ii_Unique)
|
||||||
buildstate.spool2 = _bt_spoolinit(index, false, true);
|
buildstate.spool2 = _bt_spoolinit(index, false, true);
|
||||||
|
@ -129,8 +129,8 @@ btbuild(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we are doing bottom-up btree build, finish the build by (1)
|
* if we are doing bottom-up btree build, finish the build by (1)
|
||||||
* completing the sort of the spool file, (2) inserting the sorted
|
* completing the sort of the spool file, (2) inserting the sorted tuples
|
||||||
* tuples into btree pages and (3) building the upper levels.
|
* into btree pages and (3) building the upper levels.
|
||||||
*/
|
*/
|
||||||
if (buildstate.usefast)
|
if (buildstate.usefast)
|
||||||
{
|
{
|
||||||
|
@ -176,9 +176,8 @@ btbuildCallback(Relation index,
|
||||||
btitem = _bt_formitem(itup);
|
btitem = _bt_formitem(itup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we are doing bottom-up btree build, we insert the index into a
|
* if we are doing bottom-up btree build, we insert the index into a spool
|
||||||
* spool file for subsequent processing. otherwise, we insert into
|
* file for subsequent processing. otherwise, we insert into the btree.
|
||||||
* the btree.
|
|
||||||
*/
|
*/
|
||||||
if (buildstate->usefast)
|
if (buildstate->usefast)
|
||||||
{
|
{
|
||||||
|
@ -248,16 +247,16 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||||
bool res;
|
bool res;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we've already initialized this scan, we can just advance it in
|
* If we've already initialized this scan, we can just advance it in the
|
||||||
* the appropriate direction. If we haven't done so yet, we call a
|
* appropriate direction. If we haven't done so yet, we call a routine to
|
||||||
* routine to get the first item in the scan.
|
* get the first item in the scan.
|
||||||
*/
|
*/
|
||||||
if (ItemPointerIsValid(&(scan->currentItemData)))
|
if (ItemPointerIsValid(&(scan->currentItemData)))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Restore scan position using heap TID returned by previous call
|
* Restore scan position using heap TID returned by previous call to
|
||||||
* to btgettuple(). _bt_restscan() re-grabs the read lock on the
|
* btgettuple(). _bt_restscan() re-grabs the read lock on the buffer,
|
||||||
* buffer, too.
|
* too.
|
||||||
*/
|
*/
|
||||||
_bt_restscan(scan);
|
_bt_restscan(scan);
|
||||||
|
|
||||||
|
@ -267,17 +266,16 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||||
if (scan->kill_prior_tuple)
|
if (scan->kill_prior_tuple)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Yes, so mark it by setting the LP_DELETE bit in the item
|
* Yes, so mark it by setting the LP_DELETE bit in the item flags.
|
||||||
* flags.
|
|
||||||
*/
|
*/
|
||||||
offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
|
offnum = ItemPointerGetOffsetNumber(&(scan->currentItemData));
|
||||||
page = BufferGetPage(so->btso_curbuf);
|
page = BufferGetPage(so->btso_curbuf);
|
||||||
PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
|
PageGetItemId(page, offnum)->lp_flags |= LP_DELETE;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since this can be redone later if needed, it's treated the
|
* Since this can be redone later if needed, it's treated the same
|
||||||
* same as a commit-hint-bit status update for heap tuples: we
|
* as a commit-hint-bit status update for heap tuples: we mark the
|
||||||
* mark the buffer dirty but don't make a WAL log entry.
|
* buffer dirty but don't make a WAL log entry.
|
||||||
*/
|
*/
|
||||||
SetBufferCommitInfoNeedsSave(so->btso_curbuf);
|
SetBufferCommitInfoNeedsSave(so->btso_curbuf);
|
||||||
}
|
}
|
||||||
|
@ -306,11 +304,11 @@ btgettuple(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save heap TID to use it in _bt_restscan. Then release the read
|
* Save heap TID to use it in _bt_restscan. Then release the read lock on
|
||||||
* lock on the buffer so that we aren't blocking other backends.
|
* the buffer so that we aren't blocking other backends.
|
||||||
*
|
*
|
||||||
* NOTE: we do keep the pin on the buffer! This is essential to ensure
|
* NOTE: we do keep the pin on the buffer! This is essential to ensure that
|
||||||
* that someone else doesn't delete the index entry we are stopped on.
|
* someone else doesn't delete the index entry we are stopped on.
|
||||||
*/
|
*/
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
|
@ -355,6 +353,7 @@ btgetmulti(PG_FUNCTION_ARGS)
|
||||||
res = _bt_next(scan, ForwardScanDirection);
|
res = _bt_next(scan, ForwardScanDirection);
|
||||||
else
|
else
|
||||||
res = _bt_first(scan, ForwardScanDirection);
|
res = _bt_first(scan, ForwardScanDirection);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip killed tuples if asked to.
|
* Skip killed tuples if asked to.
|
||||||
*/
|
*/
|
||||||
|
@ -381,8 +380,8 @@ btgetmulti(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save heap TID to use it in _bt_restscan. Then release the read
|
* Save heap TID to use it in _bt_restscan. Then release the read lock on
|
||||||
* lock on the buffer so that we aren't blocking other backends.
|
* the buffer so that we aren't blocking other backends.
|
||||||
*/
|
*/
|
||||||
if (res)
|
if (res)
|
||||||
{
|
{
|
||||||
|
@ -456,8 +455,8 @@ btrescan(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the scan keys. Note that keys ordering stuff moved to
|
* Reset the scan keys. Note that keys ordering stuff moved to _bt_first.
|
||||||
* _bt_first. - vadim 05/05/97
|
* - vadim 05/05/97
|
||||||
*/
|
*/
|
||||||
if (scankey && scan->numberOfKeys > 0)
|
if (scankey && scan->numberOfKeys > 0)
|
||||||
memmove(scan->keyData,
|
memmove(scan->keyData,
|
||||||
|
@ -593,21 +592,20 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||||
num_index_tuples = 0;
|
num_index_tuples = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The outer loop iterates over index leaf pages, the inner over items
|
* The outer loop iterates over index leaf pages, the inner over items on
|
||||||
* on a leaf page. We issue just one _bt_delitems() call per page, so
|
* a leaf page. We issue just one _bt_delitems() call per page, so as to
|
||||||
* as to minimize WAL traffic.
|
* minimize WAL traffic.
|
||||||
*
|
*
|
||||||
* Note that we exclusive-lock every leaf page containing data items, in
|
* Note that we exclusive-lock every leaf page containing data items, in
|
||||||
* sequence left to right. It sounds attractive to only
|
* sequence left to right. It sounds attractive to only exclusive-lock
|
||||||
* exclusive-lock those containing items we need to delete, but
|
* those containing items we need to delete, but unfortunately that is not
|
||||||
* unfortunately that is not safe: we could then pass a stopped
|
* safe: we could then pass a stopped indexscan, which could in rare cases
|
||||||
* indexscan, which could in rare cases lead to deleting the item it
|
* lead to deleting the item it needs to find when it resumes. (See
|
||||||
* needs to find when it resumes. (See _bt_restscan --- this could
|
* _bt_restscan --- this could only happen if an indexscan stops on a
|
||||||
* only happen if an indexscan stops on a deletable item and then a
|
* deletable item and then a page split moves that item into a page
|
||||||
* page split moves that item into a page further to its right, which
|
* further to its right, which the indexscan will have no pin on.) We can
|
||||||
* the indexscan will have no pin on.) We can skip obtaining
|
* skip obtaining exclusive lock on empty pages though, since no indexscan
|
||||||
* exclusive lock on empty pages though, since no indexscan could be
|
* could be stopped on those.
|
||||||
* stopped on those.
|
|
||||||
*/
|
*/
|
||||||
buf = _bt_get_endpoint(rel, 0, false);
|
buf = _bt_get_endpoint(rel, 0, false);
|
||||||
if (BufferIsValid(buf)) /* check for empty index */
|
if (BufferIsValid(buf)) /* check for empty index */
|
||||||
|
@ -632,15 +630,15 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||||
if (minoff <= maxoff && !P_ISDELETED(opaque))
|
if (minoff <= maxoff && !P_ISDELETED(opaque))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Trade in the initial read lock for a super-exclusive
|
* Trade in the initial read lock for a super-exclusive write
|
||||||
* write lock on this page.
|
* lock on this page.
|
||||||
*/
|
*/
|
||||||
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
LockBuffer(buf, BUFFER_LOCK_UNLOCK);
|
||||||
LockBufferForCleanup(buf);
|
LockBufferForCleanup(buf);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Recompute minoff/maxoff, both of which could have
|
* Recompute minoff/maxoff, both of which could have changed
|
||||||
* changed while we weren't holding the lock.
|
* while we weren't holding the lock.
|
||||||
*/
|
*/
|
||||||
minoff = P_FIRSTDATAKEY(opaque);
|
minoff = P_FIRSTDATAKEY(opaque);
|
||||||
maxoff = PageGetMaxOffsetNumber(page);
|
maxoff = PageGetMaxOffsetNumber(page);
|
||||||
|
@ -670,8 +668,8 @@ btbulkdelete(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we need to delete anything, do it and write the buffer;
|
* If we need to delete anything, do it and write the buffer; else
|
||||||
* else just release the buffer.
|
* just release the buffer.
|
||||||
*/
|
*/
|
||||||
nextpage = opaque->btpo_next;
|
nextpage = opaque->btpo_next;
|
||||||
if (ndeletable > 0)
|
if (ndeletable > 0)
|
||||||
|
@ -725,19 +723,19 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
||||||
Assert(stats != NULL);
|
Assert(stats != NULL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* First find out the number of pages in the index. We must acquire
|
* First find out the number of pages in the index. We must acquire the
|
||||||
* the relation-extension lock while doing this to avoid a race
|
* relation-extension lock while doing this to avoid a race condition: if
|
||||||
* condition: if someone else is extending the relation, there is
|
* someone else is extending the relation, there is a window where
|
||||||
* a window where bufmgr/smgr have created a new all-zero page but
|
* bufmgr/smgr have created a new all-zero page but it hasn't yet been
|
||||||
* it hasn't yet been write-locked by _bt_getbuf(). If we manage to
|
* write-locked by _bt_getbuf(). If we manage to scan such a page here,
|
||||||
* scan such a page here, we'll improperly assume it can be recycled.
|
* we'll improperly assume it can be recycled. Taking the lock
|
||||||
* Taking the lock synchronizes things enough to prevent a problem:
|
* synchronizes things enough to prevent a problem: either num_pages won't
|
||||||
* either num_pages won't include the new page, or _bt_getbuf already
|
* include the new page, or _bt_getbuf already has write lock on the
|
||||||
* has write lock on the buffer and it will be fully initialized before
|
* buffer and it will be fully initialized before we can examine it. (See
|
||||||
* we can examine it. (See also vacuumlazy.c, which has the same issue.)
|
* also vacuumlazy.c, which has the same issue.)
|
||||||
*
|
*
|
||||||
* We can skip locking for new or temp relations,
|
* We can skip locking for new or temp relations, however, since no one else
|
||||||
* however, since no one else could be accessing them.
|
* could be accessing them.
|
||||||
*/
|
*/
|
||||||
needLock = !RELATION_IS_LOCAL(rel);
|
needLock = !RELATION_IS_LOCAL(rel);
|
||||||
|
|
||||||
|
@ -807,12 +805,12 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* During VACUUM FULL it's okay to recycle deleted pages
|
* During VACUUM FULL it's okay to recycle deleted pages
|
||||||
* immediately, since there can be no other transactions
|
* immediately, since there can be no other transactions scanning
|
||||||
* scanning the index. Note that we will only recycle the
|
* the index. Note that we will only recycle the current page and
|
||||||
* current page and not any parent pages that _bt_pagedel
|
* not any parent pages that _bt_pagedel might have recursed to;
|
||||||
* might have recursed to; this seems reasonable in the name
|
* this seems reasonable in the name of simplicity. (Trying to do
|
||||||
* of simplicity. (Trying to do otherwise would mean we'd
|
* otherwise would mean we'd have to sort the list of recyclable
|
||||||
* have to sort the list of recyclable pages we're building.)
|
* pages we're building.)
|
||||||
*/
|
*/
|
||||||
if (ndel && info->vacuum_full)
|
if (ndel && info->vacuum_full)
|
||||||
{
|
{
|
||||||
|
@ -827,10 +825,10 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* During VACUUM FULL, we truncate off any recyclable pages at the end
|
* During VACUUM FULL, we truncate off any recyclable pages at the end of
|
||||||
* of the index. In a normal vacuum it'd be unsafe to do this except
|
* the index. In a normal vacuum it'd be unsafe to do this except by
|
||||||
* by acquiring exclusive lock on the index and then rechecking all
|
* acquiring exclusive lock on the index and then rechecking all the
|
||||||
* the pages; doesn't seem worth it.
|
* pages; doesn't seem worth it.
|
||||||
*/
|
*/
|
||||||
if (info->vacuum_full && nFreePages > 0)
|
if (info->vacuum_full && nFreePages > 0)
|
||||||
{
|
{
|
||||||
|
@ -857,9 +855,9 @@ btvacuumcleanup(PG_FUNCTION_ARGS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Update the shared Free Space Map with the info we now have about
|
* Update the shared Free Space Map with the info we now have about free
|
||||||
* free pages in the index, discarding any old info the map may have.
|
* pages in the index, discarding any old info the map may have. We do not
|
||||||
* We do not need to sort the page numbers; they're in order already.
|
* need to sort the page numbers; they're in order already.
|
||||||
*/
|
*/
|
||||||
RecordIndexFreeSpace(&rel->rd_node, nFreePages, freePages);
|
RecordIndexFreeSpace(&rel->rd_node, nFreePages, freePages);
|
||||||
|
|
||||||
|
@ -915,8 +913,8 @@ _bt_restscan(IndexScanDesc scan)
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We use this as flag when first index tuple on page is deleted but
|
* We use this as flag when first index tuple on page is deleted but we do
|
||||||
* we do not move left (this would slowdown vacuum) - so we set
|
* not move left (this would slowdown vacuum) - so we set
|
||||||
* current->ip_posid before first index tuple on the current page
|
* current->ip_posid before first index tuple on the current page
|
||||||
* (_bt_step will move it right)... XXX still needed?
|
* (_bt_step will move it right)... XXX still needed?
|
||||||
*/
|
*/
|
||||||
|
@ -948,12 +946,12 @@ _bt_restscan(IndexScanDesc scan)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The item we're looking for moved right at least one page, so
|
* The item we're looking for moved right at least one page, so move
|
||||||
* move right. We are careful here to pin and read-lock the next
|
* right. We are careful here to pin and read-lock the next non-dead
|
||||||
* non-dead page before releasing the current one. This ensures
|
* page before releasing the current one. This ensures that a
|
||||||
* that a concurrent btbulkdelete scan cannot pass our position
|
* concurrent btbulkdelete scan cannot pass our position --- if it
|
||||||
* --- if it did, it might be able to reach and delete our target
|
* did, it might be able to reach and delete our target item before we
|
||||||
* item before we can find it again.
|
* can find it again.
|
||||||
*/
|
*/
|
||||||
if (P_RIGHTMOST(opaque))
|
if (P_RIGHTMOST(opaque))
|
||||||
elog(ERROR, "failed to re-find previous key in \"%s\"",
|
elog(ERROR, "failed to re-find previous key in \"%s\"",
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.94 2005/10/06 02:29:12 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsearch.c,v 1.95 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -69,9 +69,9 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
|
||||||
BTStack new_stack;
|
BTStack new_stack;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Race -- the page we just grabbed may have split since we read
|
* Race -- the page we just grabbed may have split since we read its
|
||||||
* its pointer in the parent (or metapage). If it has, we may
|
* pointer in the parent (or metapage). If it has, we may need to
|
||||||
* need to move right to its new sibling. Do that.
|
* move right to its new sibling. Do that.
|
||||||
*/
|
*/
|
||||||
*bufP = _bt_moveright(rel, *bufP, keysz, scankey, nextkey, BT_READ);
|
*bufP = _bt_moveright(rel, *bufP, keysz, scankey, nextkey, BT_READ);
|
||||||
|
|
||||||
|
@ -82,8 +82,8 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find the appropriate item on the internal page, and get the
|
* Find the appropriate item on the internal page, and get the child
|
||||||
* child page that it points to.
|
* page that it points to.
|
||||||
*/
|
*/
|
||||||
offnum = _bt_binsrch(rel, *bufP, keysz, scankey, nextkey);
|
offnum = _bt_binsrch(rel, *bufP, keysz, scankey, nextkey);
|
||||||
itemid = PageGetItemId(page, offnum);
|
itemid = PageGetItemId(page, offnum);
|
||||||
|
@ -94,13 +94,13 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to save the location of the index entry we chose in the
|
* We need to save the location of the index entry we chose in the
|
||||||
* parent page on a stack. In case we split the tree, we'll use
|
* parent page on a stack. In case we split the tree, we'll use the
|
||||||
* the stack to work back up to the parent page. We also save the
|
* stack to work back up to the parent page. We also save the actual
|
||||||
* actual downlink (TID) to uniquely identify the index entry, in
|
* downlink (TID) to uniquely identify the index entry, in case it
|
||||||
* case it moves right while we're working lower in the tree. See
|
* moves right while we're working lower in the tree. See the paper
|
||||||
* the paper by Lehman and Yao for how this is detected and
|
* by Lehman and Yao for how this is detected and handled. (We use the
|
||||||
* handled. (We use the child link to disambiguate duplicate keys
|
* child link to disambiguate duplicate keys in the index -- Lehman
|
||||||
* in the index -- Lehman and Yao disallow duplicate keys.)
|
* and Yao disallow duplicate keys.)
|
||||||
*/
|
*/
|
||||||
new_stack = (BTStack) palloc(sizeof(BTStackData));
|
new_stack = (BTStack) palloc(sizeof(BTStackData));
|
||||||
new_stack->bts_blkno = par_blkno;
|
new_stack->bts_blkno = par_blkno;
|
||||||
|
@ -156,19 +156,18 @@ _bt_moveright(Relation rel,
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When nextkey = false (normal case): if the scan key that brought us
|
* When nextkey = false (normal case): if the scan key that brought us to
|
||||||
* to this page is > the high key stored on the page, then the page
|
* this page is > the high key stored on the page, then the page has split
|
||||||
* has split and we need to move right. (If the scan key is equal to
|
* and we need to move right. (If the scan key is equal to the high key,
|
||||||
* the high key, we might or might not need to move right; have to
|
* we might or might not need to move right; have to scan the page first
|
||||||
* scan the page first anyway.)
|
* anyway.)
|
||||||
*
|
*
|
||||||
* When nextkey = true: move right if the scan key is >= page's high key.
|
* When nextkey = true: move right if the scan key is >= page's high key.
|
||||||
*
|
*
|
||||||
* The page could even have split more than once, so scan as far as
|
* The page could even have split more than once, so scan as far as needed.
|
||||||
* needed.
|
|
||||||
*
|
*
|
||||||
* We also have to move right if we followed a link that brought us to a
|
* We also have to move right if we followed a link that brought us to a dead
|
||||||
* dead page.
|
* page.
|
||||||
*/
|
*/
|
||||||
cmpval = nextkey ? 0 : 1;
|
cmpval = nextkey ? 0 : 1;
|
||||||
|
|
||||||
|
@ -242,24 +241,24 @@ _bt_binsrch(Relation rel,
|
||||||
high = PageGetMaxOffsetNumber(page);
|
high = PageGetMaxOffsetNumber(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are no keys on the page, return the first available slot.
|
* If there are no keys on the page, return the first available slot. Note
|
||||||
* Note this covers two cases: the page is really empty (no keys), or
|
* this covers two cases: the page is really empty (no keys), or it
|
||||||
* it contains only a high key. The latter case is possible after
|
* contains only a high key. The latter case is possible after vacuuming.
|
||||||
* vacuuming. This can never happen on an internal page, however,
|
* This can never happen on an internal page, however, since they are
|
||||||
* since they are never empty (an internal page must have children).
|
* never empty (an internal page must have children).
|
||||||
*/
|
*/
|
||||||
if (high < low)
|
if (high < low)
|
||||||
return low;
|
return low;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Binary search to find the first key on the page >= scan key, or
|
* Binary search to find the first key on the page >= scan key, or first
|
||||||
* first key > scankey when nextkey is true.
|
* key > scankey when nextkey is true.
|
||||||
*
|
*
|
||||||
* For nextkey=false (cmpval=1), the loop invariant is: all slots before
|
* For nextkey=false (cmpval=1), the loop invariant is: all slots before
|
||||||
* 'low' are < scan key, all slots at or after 'high' are >= scan key.
|
* 'low' are < scan key, all slots at or after 'high' are >= scan key.
|
||||||
*
|
*
|
||||||
* For nextkey=true (cmpval=0), the loop invariant is: all slots before
|
* For nextkey=true (cmpval=0), the loop invariant is: all slots before 'low'
|
||||||
* 'low' are <= scan key, all slots at or after 'high' are > scan key.
|
* are <= scan key, all slots at or after 'high' are > scan key.
|
||||||
*
|
*
|
||||||
* We can fall out when high == low.
|
* We can fall out when high == low.
|
||||||
*/
|
*/
|
||||||
|
@ -285,15 +284,15 @@ _bt_binsrch(Relation rel,
|
||||||
* At this point we have high == low, but be careful: they could point
|
* At this point we have high == low, but be careful: they could point
|
||||||
* past the last slot on the page.
|
* past the last slot on the page.
|
||||||
*
|
*
|
||||||
* On a leaf page, we always return the first key >= scan key (resp. >
|
* On a leaf page, we always return the first key >= scan key (resp. > scan
|
||||||
* scan key), which could be the last slot + 1.
|
* key), which could be the last slot + 1.
|
||||||
*/
|
*/
|
||||||
if (P_ISLEAF(opaque))
|
if (P_ISLEAF(opaque))
|
||||||
return low;
|
return low;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* On a non-leaf page, return the last key < scan key (resp. <= scan
|
* On a non-leaf page, return the last key < scan key (resp. <= scan key).
|
||||||
* key). There must be one if _bt_compare() is playing by the rules.
|
* There must be one if _bt_compare() is playing by the rules.
|
||||||
*/
|
*/
|
||||||
Assert(low > P_FIRSTDATAKEY(opaque));
|
Assert(low > P_FIRSTDATAKEY(opaque));
|
||||||
|
|
||||||
|
@ -337,8 +336,8 @@ _bt_compare(Relation rel,
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Force result ">" if target item is first data item on an internal
|
* Force result ">" if target item is first data item on an internal page
|
||||||
* page --- see NOTE above.
|
* --- see NOTE above.
|
||||||
*/
|
*/
|
||||||
if (!P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
|
if (!P_ISLEAF(opaque) && offnum == P_FIRSTDATAKEY(opaque))
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -347,15 +346,15 @@ _bt_compare(Relation rel,
|
||||||
itup = &(btitem->bti_itup);
|
itup = &(btitem->bti_itup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The scan key is set up with the attribute number associated with
|
* The scan key is set up with the attribute number associated with each
|
||||||
* each term in the key. It is important that, if the index is
|
* term in the key. It is important that, if the index is multi-key, the
|
||||||
* multi-key, the scan contain the first k key attributes, and that
|
* scan contain the first k key attributes, and that they be in order. If
|
||||||
* they be in order. If you think about how multi-key ordering works,
|
* you think about how multi-key ordering works, you'll understand why
|
||||||
* you'll understand why this is.
|
* this is.
|
||||||
*
|
*
|
||||||
* We don't test for violation of this condition here, however. The
|
* We don't test for violation of this condition here, however. The initial
|
||||||
* initial setup for the index scan had better have gotten it right
|
* setup for the index scan had better have gotten it right (see
|
||||||
* (see _bt_first).
|
* _bt_first).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
for (i = 1; i <= keysz; i++)
|
for (i = 1; i <= keysz; i++)
|
||||||
|
@ -381,15 +380,15 @@ _bt_compare(Relation rel,
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* The sk_func needs to be passed the index value as left arg
|
* The sk_func needs to be passed the index value as left arg and
|
||||||
* and the sk_argument as right arg (they might be of
|
* the sk_argument as right arg (they might be of different
|
||||||
* different types). Since it is convenient for callers to
|
* types). Since it is convenient for callers to think of
|
||||||
* think of _bt_compare as comparing the scankey to the index
|
* _bt_compare as comparing the scankey to the index item, we have
|
||||||
* item, we have to flip the sign of the comparison result.
|
* to flip the sign of the comparison result.
|
||||||
*
|
*
|
||||||
* Note: curious-looking coding is to avoid overflow if
|
* Note: curious-looking coding is to avoid overflow if comparison
|
||||||
* comparison function returns INT_MIN. There is no risk of
|
* function returns INT_MIN. There is no risk of overflow for
|
||||||
* overflow for positive results.
|
* positive results.
|
||||||
*/
|
*/
|
||||||
result = DatumGetInt32(FunctionCall2(&scankey->sk_func,
|
result = DatumGetInt32(FunctionCall2(&scankey->sk_func,
|
||||||
datum,
|
datum,
|
||||||
|
@ -505,8 +504,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
pgstat_count_index_scan(&scan->xs_pgstat_info);
|
pgstat_count_index_scan(&scan->xs_pgstat_info);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Examine the scan keys and eliminate any redundant keys; also
|
* Examine the scan keys and eliminate any redundant keys; also discover
|
||||||
* discover how many keys must be matched to continue the scan.
|
* how many keys must be matched to continue the scan.
|
||||||
*/
|
*/
|
||||||
_bt_preprocess_keys(scan);
|
_bt_preprocess_keys(scan);
|
||||||
|
|
||||||
|
@ -556,9 +555,9 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
ScanKey cur;
|
ScanKey cur;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* chosen is the so-far-chosen key for the current attribute, if
|
* chosen is the so-far-chosen key for the current attribute, if any.
|
||||||
* any. We don't cast the decision in stone until we reach keys
|
* We don't cast the decision in stone until we reach keys for the
|
||||||
* for the next attribute.
|
* next attribute.
|
||||||
*/
|
*/
|
||||||
curattr = 1;
|
curattr = 1;
|
||||||
chosen = NULL;
|
chosen = NULL;
|
||||||
|
@ -595,9 +594,9 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Done if that was the last attribute, or if next key
|
* Done if that was the last attribute, or if next key is not
|
||||||
* is not in sequence (implying no boundary key is available
|
* in sequence (implying no boundary key is available for the
|
||||||
* for the next attribute).
|
* next attribute).
|
||||||
*/
|
*/
|
||||||
if (i >= so->numberOfKeys ||
|
if (i >= so->numberOfKeys ||
|
||||||
cur->sk_attno != curattr + 1)
|
cur->sk_attno != curattr + 1)
|
||||||
|
@ -632,17 +631,17 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we found no usable boundary keys, we have to start from one end
|
* If we found no usable boundary keys, we have to start from one end of
|
||||||
* of the tree. Walk down that edge to the first or last key, and
|
* the tree. Walk down that edge to the first or last key, and scan from
|
||||||
* scan from there.
|
* there.
|
||||||
*/
|
*/
|
||||||
if (keysCount == 0)
|
if (keysCount == 0)
|
||||||
return _bt_endpoint(scan, dir);
|
return _bt_endpoint(scan, dir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to start the scan somewhere within the index. Set up a
|
* We want to start the scan somewhere within the index. Set up a
|
||||||
* 3-way-comparison scankey we can use to search for the boundary
|
* 3-way-comparison scankey we can use to search for the boundary point we
|
||||||
* point we identified above.
|
* identified above.
|
||||||
*/
|
*/
|
||||||
Assert(keysCount <= INDEX_MAX_KEYS);
|
Assert(keysCount <= INDEX_MAX_KEYS);
|
||||||
for (i = 0; i < keysCount; i++)
|
for (i = 0; i < keysCount; i++)
|
||||||
|
@ -650,16 +649,15 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
ScanKey cur = startKeys[i];
|
ScanKey cur = startKeys[i];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* _bt_preprocess_keys disallows it, but it's place to add some
|
* _bt_preprocess_keys disallows it, but it's place to add some code
|
||||||
* code later
|
* later
|
||||||
*/
|
*/
|
||||||
if (cur->sk_flags & SK_ISNULL)
|
if (cur->sk_flags & SK_ISNULL)
|
||||||
elog(ERROR, "btree doesn't support is(not)null, yet");
|
elog(ERROR, "btree doesn't support is(not)null, yet");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If scankey operator is of default subtype, we can use the
|
* If scankey operator is of default subtype, we can use the cached
|
||||||
* cached comparison procedure; otherwise gotta look it up in the
|
* comparison procedure; otherwise gotta look it up in the catalogs.
|
||||||
* catalogs.
|
|
||||||
*/
|
*/
|
||||||
if (cur->sk_subtype == InvalidOid)
|
if (cur->sk_subtype == InvalidOid)
|
||||||
{
|
{
|
||||||
|
@ -692,13 +690,13 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Examine the selected initial-positioning strategy to determine
|
* Examine the selected initial-positioning strategy to determine exactly
|
||||||
* exactly where we need to start the scan, and set flag variables to
|
* where we need to start the scan, and set flag variables to control the
|
||||||
* control the code below.
|
* code below.
|
||||||
*
|
*
|
||||||
* If nextkey = false, _bt_search and _bt_binsrch will locate the first
|
* If nextkey = false, _bt_search and _bt_binsrch will locate the first item
|
||||||
* item >= scan key. If nextkey = true, they will locate the first
|
* >= scan key. If nextkey = true, they will locate the first item > scan
|
||||||
* item > scan key.
|
* key.
|
||||||
*
|
*
|
||||||
* If goback = true, we will then step back one item, while if goback =
|
* If goback = true, we will then step back one item, while if goback =
|
||||||
* false, we will start the scan on the located item.
|
* false, we will start the scan on the located item.
|
||||||
|
@ -710,10 +708,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
case BTLessStrategyNumber:
|
case BTLessStrategyNumber:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find first item >= scankey, then back up one to arrive at
|
* Find first item >= scankey, then back up one to arrive at last
|
||||||
* last item < scankey. (Note: this positioning strategy is
|
* item < scankey. (Note: this positioning strategy is only used
|
||||||
* only used for a backward scan, so that is always the
|
* for a backward scan, so that is always the correct starting
|
||||||
* correct starting position.)
|
* position.)
|
||||||
*/
|
*/
|
||||||
nextkey = false;
|
nextkey = false;
|
||||||
goback = true;
|
goback = true;
|
||||||
|
@ -722,10 +720,10 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
case BTLessEqualStrategyNumber:
|
case BTLessEqualStrategyNumber:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Find first item > scankey, then back up one to arrive at
|
* Find first item > scankey, then back up one to arrive at last
|
||||||
* last item <= scankey. (Note: this positioning strategy is
|
* item <= scankey. (Note: this positioning strategy is only used
|
||||||
* only used for a backward scan, so that is always the
|
* for a backward scan, so that is always the correct starting
|
||||||
* correct starting position.)
|
* position.)
|
||||||
*/
|
*/
|
||||||
nextkey = true;
|
nextkey = true;
|
||||||
goback = true;
|
goback = true;
|
||||||
|
@ -734,14 +732,14 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
case BTEqualStrategyNumber:
|
case BTEqualStrategyNumber:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If a backward scan was specified, need to start with last
|
* If a backward scan was specified, need to start with last equal
|
||||||
* equal item not first one.
|
* item not first one.
|
||||||
*/
|
*/
|
||||||
if (ScanDirectionIsBackward(dir))
|
if (ScanDirectionIsBackward(dir))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is the same as the <= strategy. We will check at
|
* This is the same as the <= strategy. We will check at the
|
||||||
* the end whether the found item is actually =.
|
* end whether the found item is actually =.
|
||||||
*/
|
*/
|
||||||
nextkey = true;
|
nextkey = true;
|
||||||
goback = true;
|
goback = true;
|
||||||
|
@ -749,8 +747,8 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* This is the same as the >= strategy. We will check at
|
* This is the same as the >= strategy. We will check at the
|
||||||
* the end whether the found item is actually =.
|
* end whether the found item is actually =.
|
||||||
*/
|
*/
|
||||||
nextkey = false;
|
nextkey = false;
|
||||||
goback = false;
|
goback = false;
|
||||||
|
@ -813,24 +811,24 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
|
||||||
ItemPointerSet(current, blkno, offnum);
|
ItemPointerSet(current, blkno, offnum);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If nextkey = false, we are positioned at the first item >= scan
|
* If nextkey = false, we are positioned at the first item >= scan key, or
|
||||||
* key, or possibly at the end of a page on which all the existing
|
* possibly at the end of a page on which all the existing items are less
|
||||||
* items are less than the scan key and we know that everything on
|
* than the scan key and we know that everything on later pages is greater
|
||||||
* later pages is greater than or equal to scan key.
|
* than or equal to scan key.
|
||||||
*
|
*
|
||||||
* If nextkey = true, we are positioned at the first item > scan key, or
|
* If nextkey = true, we are positioned at the first item > scan key, or
|
||||||
* possibly at the end of a page on which all the existing items are
|
* possibly at the end of a page on which all the existing items are less
|
||||||
* less than or equal to the scan key and we know that everything on
|
* than or equal to the scan key and we know that everything on later
|
||||||
* later pages is greater than scan key.
|
* pages is greater than scan key.
|
||||||
*
|
*
|
||||||
* The actually desired starting point is either this item or the prior
|
* The actually desired starting point is either this item or the prior one,
|
||||||
* one, or in the end-of-page case it's the first item on the next
|
* or in the end-of-page case it's the first item on the next page or the
|
||||||
* page or the last item on this page. We apply _bt_step if needed to
|
* last item on this page. We apply _bt_step if needed to get to the
|
||||||
* get to the right place.
|
* right place.
|
||||||
*
|
*
|
||||||
* If _bt_step fails (meaning we fell off the end of the index in one
|
* If _bt_step fails (meaning we fell off the end of the index in one
|
||||||
* direction or the other), then there are no matches so we just
|
* direction or the other), then there are no matches so we just return
|
||||||
* return false.
|
* false.
|
||||||
*/
|
*/
|
||||||
if (goback)
|
if (goback)
|
||||||
{
|
{
|
||||||
|
@ -902,8 +900,8 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||||
BlockNumber blkno;
|
BlockNumber blkno;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Don't use ItemPointerGetOffsetNumber or you risk to get assertion
|
* Don't use ItemPointerGetOffsetNumber or you risk to get assertion due
|
||||||
* due to ability of ip_posid to be equal 0.
|
* to ability of ip_posid to be equal 0.
|
||||||
*/
|
*/
|
||||||
offnum = current->ip_posid;
|
offnum = current->ip_posid;
|
||||||
|
|
||||||
|
@ -954,9 +952,9 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||||
/*
|
/*
|
||||||
* Walk left to the next page with data. This is much more
|
* Walk left to the next page with data. This is much more
|
||||||
* complex than the walk-right case because of the possibility
|
* complex than the walk-right case because of the possibility
|
||||||
* that the page to our left splits while we are in flight to
|
* that the page to our left splits while we are in flight to it,
|
||||||
* it, plus the possibility that the page we were on gets
|
* plus the possibility that the page we were on gets deleted
|
||||||
* deleted after we leave it. See nbtree/README for details.
|
* after we leave it. See nbtree/README for details.
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -973,9 +971,9 @@ _bt_step(IndexScanDesc scan, Buffer *bufP, ScanDirection dir)
|
||||||
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay, we managed to move left to a non-deleted page.
|
* Okay, we managed to move left to a non-deleted page. Done
|
||||||
* Done if it's not half-dead and not empty. Else loop
|
* if it's not half-dead and not empty. Else loop back and do
|
||||||
* back and do it all again.
|
* it all again.
|
||||||
*/
|
*/
|
||||||
if (!P_IGNORE(opaque))
|
if (!P_IGNORE(opaque))
|
||||||
{
|
{
|
||||||
|
@ -1043,15 +1041,14 @@ _bt_walk_left(Relation rel, Buffer buf)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If this isn't the page we want, walk right till we find what we
|
* If this isn't the page we want, walk right till we find what we
|
||||||
* want --- but go no more than four hops (an arbitrary limit). If
|
* want --- but go no more than four hops (an arbitrary limit). If we
|
||||||
* we don't find the correct page by then, the most likely bet is
|
* don't find the correct page by then, the most likely bet is that
|
||||||
* that the original page got deleted and isn't in the sibling
|
* the original page got deleted and isn't in the sibling chain at all
|
||||||
* chain at all anymore, not that its left sibling got split more
|
* anymore, not that its left sibling got split more than four times.
|
||||||
* than four times.
|
|
||||||
*
|
*
|
||||||
* Note that it is correct to test P_ISDELETED not P_IGNORE here,
|
* Note that it is correct to test P_ISDELETED not P_IGNORE here, because
|
||||||
* because half-dead pages are still in the sibling chain. Caller
|
* half-dead pages are still in the sibling chain. Caller must reject
|
||||||
* must reject half-dead pages if wanted.
|
* half-dead pages if wanted.
|
||||||
*/
|
*/
|
||||||
tries = 0;
|
tries = 0;
|
||||||
for (;;)
|
for (;;)
|
||||||
|
@ -1077,9 +1074,9 @@ _bt_walk_left(Relation rel, Buffer buf)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* It was deleted. Move right to first nondeleted page (there
|
* It was deleted. Move right to first nondeleted page (there
|
||||||
* must be one); that is the page that has acquired the
|
* must be one); that is the page that has acquired the deleted
|
||||||
* deleted one's keyspace, so stepping left from it will take
|
* one's keyspace, so stepping left from it will take us where we
|
||||||
* us where we want to be.
|
* want to be.
|
||||||
*/
|
*/
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
@ -1095,16 +1092,16 @@ _bt_walk_left(Relation rel, Buffer buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now return to top of loop, resetting obknum to point to
|
* Now return to top of loop, resetting obknum to point to this
|
||||||
* this nondeleted page, and try again.
|
* nondeleted page, and try again.
|
||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* It wasn't deleted; the explanation had better be that the
|
* It wasn't deleted; the explanation had better be that the page
|
||||||
* page to the left got split or deleted. Without this check,
|
* to the left got split or deleted. Without this check, we'd go
|
||||||
* we'd go into an infinite loop if there's anything wrong.
|
* into an infinite loop if there's anything wrong.
|
||||||
*/
|
*/
|
||||||
if (opaque->btpo_prev == lblkno)
|
if (opaque->btpo_prev == lblkno)
|
||||||
elog(ERROR, "could not find left sibling in \"%s\"",
|
elog(ERROR, "could not find left sibling in \"%s\"",
|
||||||
|
@ -1137,8 +1134,8 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are looking for a leaf page, okay to descend from fast root;
|
* If we are looking for a leaf page, okay to descend from fast root;
|
||||||
* otherwise better descend from true root. (There is no point in
|
* otherwise better descend from true root. (There is no point in being
|
||||||
* being smarter about intermediate levels.)
|
* smarter about intermediate levels.)
|
||||||
*/
|
*/
|
||||||
if (level == 0)
|
if (level == 0)
|
||||||
buf = _bt_getroot(rel, BT_READ);
|
buf = _bt_getroot(rel, BT_READ);
|
||||||
|
@ -1159,8 +1156,8 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
|
||||||
/*
|
/*
|
||||||
* If we landed on a deleted page, step right to find a live page
|
* If we landed on a deleted page, step right to find a live page
|
||||||
* (there must be one). Also, if we want the rightmost page, step
|
* (there must be one). Also, if we want the rightmost page, step
|
||||||
* right if needed to get to it (this could happen if the page
|
* right if needed to get to it (this could happen if the page split
|
||||||
* split since we obtained a pointer to it).
|
* since we obtained a pointer to it).
|
||||||
*/
|
*/
|
||||||
while (P_IGNORE(opaque) ||
|
while (P_IGNORE(opaque) ||
|
||||||
(rightmost && !P_RIGHTMOST(opaque)))
|
(rightmost && !P_RIGHTMOST(opaque)))
|
||||||
|
@ -1228,9 +1225,9 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||||
so = (BTScanOpaque) scan->opaque;
|
so = (BTScanOpaque) scan->opaque;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Scan down to the leftmost or rightmost leaf page. This is a
|
* Scan down to the leftmost or rightmost leaf page. This is a simplified
|
||||||
* simplified version of _bt_search(). We don't maintain a stack
|
* version of _bt_search(). We don't maintain a stack since we know we
|
||||||
* since we know we won't need it.
|
* won't need it.
|
||||||
*/
|
*/
|
||||||
buf = _bt_get_endpoint(rel, 0, ScanDirectionIsBackward(dir));
|
buf = _bt_get_endpoint(rel, 0, ScanDirectionIsBackward(dir));
|
||||||
|
|
||||||
|
@ -1261,8 +1258,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||||
Assert(P_RIGHTMOST(opaque));
|
Assert(P_RIGHTMOST(opaque));
|
||||||
|
|
||||||
start = PageGetMaxOffsetNumber(page);
|
start = PageGetMaxOffsetNumber(page);
|
||||||
if (start < P_FIRSTDATAKEY(opaque)) /* watch out for empty
|
if (start < P_FIRSTDATAKEY(opaque)) /* watch out for empty page */
|
||||||
* page */
|
|
||||||
start = P_FIRSTDATAKEY(opaque);
|
start = P_FIRSTDATAKEY(opaque);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -1276,8 +1272,8 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||||
so->btso_curbuf = buf;
|
so->btso_curbuf = buf;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Left/rightmost page could be empty due to deletions, if so step
|
* Left/rightmost page could be empty due to deletions, if so step till we
|
||||||
* till we find a nonempty page.
|
* find a nonempty page.
|
||||||
*/
|
*/
|
||||||
if (start > maxoff)
|
if (start > maxoff)
|
||||||
{
|
{
|
||||||
|
@ -1291,8 +1287,7 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
|
||||||
itup = &(btitem->bti_itup);
|
itup = &(btitem->bti_itup);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Okay, we are on the first or last tuple. Does it pass all the
|
* Okay, we are on the first or last tuple. Does it pass all the quals?
|
||||||
* quals?
|
|
||||||
*/
|
*/
|
||||||
if (_bt_checkkeys(scan, itup, dir, &continuescan))
|
if (_bt_checkkeys(scan, itup, dir, &continuescan))
|
||||||
{
|
{
|
||||||
|
|
|
@ -56,7 +56,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.94 2005/08/11 13:22:33 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtsort.c,v 1.95 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -99,12 +99,10 @@ typedef struct BTPageState
|
||||||
{
|
{
|
||||||
Page btps_page; /* workspace for page building */
|
Page btps_page; /* workspace for page building */
|
||||||
BlockNumber btps_blkno; /* block # to write this page at */
|
BlockNumber btps_blkno; /* block # to write this page at */
|
||||||
BTItem btps_minkey; /* copy of minimum key (first item) on
|
BTItem btps_minkey; /* copy of minimum key (first item) on page */
|
||||||
* page */
|
|
||||||
OffsetNumber btps_lastoff; /* last item offset loaded */
|
OffsetNumber btps_lastoff; /* last item offset loaded */
|
||||||
uint32 btps_level; /* tree level (0 = leaf) */
|
uint32 btps_level; /* tree level (0 = leaf) */
|
||||||
Size btps_full; /* "full" if less than this much free
|
Size btps_full; /* "full" if less than this much free space */
|
||||||
* space */
|
|
||||||
struct BTPageState *btps_next; /* link to parent level, if any */
|
struct BTPageState *btps_next; /* link to parent level, if any */
|
||||||
} BTPageState;
|
} BTPageState;
|
||||||
|
|
||||||
|
@ -157,21 +155,21 @@ _bt_spoolinit(Relation index, bool isunique, bool isdead)
|
||||||
btspool->isunique = isunique;
|
btspool->isunique = isunique;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We size the sort area as maintenance_work_mem rather than work_mem
|
* We size the sort area as maintenance_work_mem rather than work_mem to
|
||||||
* to speed index creation. This should be OK since a single backend
|
* speed index creation. This should be OK since a single backend can't
|
||||||
* can't run multiple index creations in parallel. Note that creation
|
* run multiple index creations in parallel. Note that creation of a
|
||||||
* of a unique index actually requires two BTSpool objects. We expect
|
* unique index actually requires two BTSpool objects. We expect that the
|
||||||
* that the second one (for dead tuples) won't get very full, so we
|
* second one (for dead tuples) won't get very full, so we give it only
|
||||||
* give it only work_mem.
|
* work_mem.
|
||||||
*/
|
*/
|
||||||
btKbytes = isdead ? work_mem : maintenance_work_mem;
|
btKbytes = isdead ? work_mem : maintenance_work_mem;
|
||||||
btspool->sortstate = tuplesort_begin_index(index, isunique,
|
btspool->sortstate = tuplesort_begin_index(index, isunique,
|
||||||
btKbytes, false);
|
btKbytes, false);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Currently, tuplesort provides sort functions on IndexTuples. If we
|
* Currently, tuplesort provides sort functions on IndexTuples. If we kept
|
||||||
* kept anything in a BTItem other than a regular IndexTuple, we'd
|
* anything in a BTItem other than a regular IndexTuple, we'd need to
|
||||||
* need to modify tuplesort to understand BTItems as such.
|
* modify tuplesort to understand BTItems as such.
|
||||||
*/
|
*/
|
||||||
Assert(sizeof(BTItemData) == sizeof(IndexTupleData));
|
Assert(sizeof(BTItemData) == sizeof(IndexTupleData));
|
||||||
|
|
||||||
|
@ -222,8 +220,8 @@ _bt_leafbuild(BTSpool *btspool, BTSpool *btspool2)
|
||||||
wstate.index = btspool->index;
|
wstate.index = btspool->index;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We need to log index creation in WAL iff WAL archiving is enabled
|
* We need to log index creation in WAL iff WAL archiving is enabled AND
|
||||||
* AND it's not a temp index.
|
* it's not a temp index.
|
||||||
*/
|
*/
|
||||||
wstate.btws_use_wal = XLogArchivingActive() && !wstate.index->rd_istemp;
|
wstate.btws_use_wal = XLogArchivingActive() && !wstate.index->rd_istemp;
|
||||||
|
|
||||||
|
@ -313,9 +311,9 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
|
||||||
/*
|
/*
|
||||||
* If we have to write pages nonsequentially, fill in the space with
|
* If we have to write pages nonsequentially, fill in the space with
|
||||||
* zeroes until we come back and overwrite. This is not logically
|
* zeroes until we come back and overwrite. This is not logically
|
||||||
* necessary on standard Unix filesystems (unwritten space will read
|
* necessary on standard Unix filesystems (unwritten space will read as
|
||||||
* as zeroes anyway), but it should help to avoid fragmentation. The
|
* zeroes anyway), but it should help to avoid fragmentation. The dummy
|
||||||
* dummy pages aren't WAL-logged though.
|
* pages aren't WAL-logged though.
|
||||||
*/
|
*/
|
||||||
while (blkno > wstate->btws_pages_written)
|
while (blkno > wstate->btws_pages_written)
|
||||||
{
|
{
|
||||||
|
@ -328,8 +326,8 @@ _bt_blwritepage(BTWriteState *wstate, Page page, BlockNumber blkno)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now write the page. We say isTemp = true even if it's not a temp
|
* Now write the page. We say isTemp = true even if it's not a temp
|
||||||
* index, because there's no need for smgr to schedule an fsync for
|
* index, because there's no need for smgr to schedule an fsync for this
|
||||||
* this write; we'll do it ourselves before ending the build.
|
* write; we'll do it ourselves before ending the build.
|
||||||
*/
|
*/
|
||||||
smgrwrite(wstate->index->rd_smgr, blkno, (char *) page, true);
|
smgrwrite(wstate->index->rd_smgr, blkno, (char *) page, true);
|
||||||
|
|
||||||
|
@ -483,15 +481,15 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||||
btisz = MAXALIGN(btisz);
|
btisz = MAXALIGN(btisz);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether the item can fit on a btree page at all. (Eventually,
|
* Check whether the item can fit on a btree page at all. (Eventually, we
|
||||||
* we ought to try to apply TOAST methods if not.) We actually need to
|
* ought to try to apply TOAST methods if not.) We actually need to be
|
||||||
* be able to fit three items on every page, so restrict any one item
|
* able to fit three items on every page, so restrict any one item to 1/3
|
||||||
* to 1/3 the per-page available space. Note that at this point, btisz
|
* the per-page available space. Note that at this point, btisz doesn't
|
||||||
* doesn't include the ItemId.
|
* include the ItemId.
|
||||||
*
|
*
|
||||||
* NOTE: similar code appears in _bt_insertonpg() to defend against
|
* NOTE: similar code appears in _bt_insertonpg() to defend against oversize
|
||||||
* oversize items being inserted into an already-existing index. But
|
* items being inserted into an already-existing index. But during
|
||||||
* during creation of an index, we don't go through there.
|
* creation of an index, we don't go through there.
|
||||||
*/
|
*/
|
||||||
if (btisz > BTMaxItemSize(npage))
|
if (btisz > BTMaxItemSize(npage))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -523,11 +521,11 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We copy the last item on the page into the new page, and then
|
* We copy the last item on the page into the new page, and then
|
||||||
* rearrange the old page so that the 'last item' becomes its high
|
* rearrange the old page so that the 'last item' becomes its high key
|
||||||
* key rather than a true data item. There had better be at least
|
* rather than a true data item. There had better be at least two
|
||||||
* two items on the page already, else the page would be empty of
|
* items on the page already, else the page would be empty of useful
|
||||||
* useful data. (Hence, we must allow pages to be packed at least
|
* data. (Hence, we must allow pages to be packed at least 2/3rds
|
||||||
* 2/3rds full; the 70% figure used above is close to minimum.)
|
* full; the 70% figure used above is close to minimum.)
|
||||||
*/
|
*/
|
||||||
Assert(last_off > P_FIRSTKEY);
|
Assert(last_off > P_FIRSTKEY);
|
||||||
ii = PageGetItemId(opage, last_off);
|
ii = PageGetItemId(opage, last_off);
|
||||||
|
@ -544,8 +542,8 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Link the old page into its parent, using its minimum key. If we
|
* Link the old page into its parent, using its minimum key. If we
|
||||||
* don't have a parent, we have to create one; this adds a new
|
* don't have a parent, we have to create one; this adds a new btree
|
||||||
* btree level.
|
* level.
|
||||||
*/
|
*/
|
||||||
if (state->btps_next == NULL)
|
if (state->btps_next == NULL)
|
||||||
state->btps_next = _bt_pagestate(wstate, state->btps_level + 1);
|
state->btps_next = _bt_pagestate(wstate, state->btps_level + 1);
|
||||||
|
@ -557,9 +555,9 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||||
pfree(state->btps_minkey);
|
pfree(state->btps_minkey);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save a copy of the minimum key for the new page. We have to
|
* Save a copy of the minimum key for the new page. We have to copy
|
||||||
* copy it off the old page, not the new one, in case we are not
|
* it off the old page, not the new one, in case we are not at leaf
|
||||||
* at leaf level.
|
* level.
|
||||||
*/
|
*/
|
||||||
state->btps_minkey = _bt_formitem(&(obti->bti_itup));
|
state->btps_minkey = _bt_formitem(&(obti->bti_itup));
|
||||||
|
|
||||||
|
@ -576,8 +574,8 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Write out the old page. We never need to touch it again, so we
|
* Write out the old page. We never need to touch it again, so we can
|
||||||
* can free the opage workspace too.
|
* free the opage workspace too.
|
||||||
*/
|
*/
|
||||||
_bt_blwritepage(wstate, opage, oblkno);
|
_bt_blwritepage(wstate, opage, oblkno);
|
||||||
|
|
||||||
|
@ -588,10 +586,10 @@ _bt_buildadd(BTWriteState *wstate, BTPageState *state, BTItem bti)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the new item is the first for its page, stash a copy for later.
|
* If the new item is the first for its page, stash a copy for later. Note
|
||||||
* Note this will only happen for the first item on a level; on later
|
* this will only happen for the first item on a level; on later pages,
|
||||||
* pages, the first item for a page is copied from the prior page in
|
* the first item for a page is copied from the prior page in the code
|
||||||
* the code above.
|
* above.
|
||||||
*/
|
*/
|
||||||
if (last_off == P_HIKEY)
|
if (last_off == P_HIKEY)
|
||||||
{
|
{
|
||||||
|
@ -636,9 +634,9 @@ _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
|
||||||
* We have to link the last page on this level to somewhere.
|
* We have to link the last page on this level to somewhere.
|
||||||
*
|
*
|
||||||
* If we're at the top, it's the root, so attach it to the metapage.
|
* If we're at the top, it's the root, so attach it to the metapage.
|
||||||
* Otherwise, add an entry for it to its parent using its minimum
|
* Otherwise, add an entry for it to its parent using its minimum key.
|
||||||
* key. This may cause the last page of the parent level to
|
* This may cause the last page of the parent level to split, but
|
||||||
* split, but that's not a problem -- we haven't gotten to it yet.
|
* that's not a problem -- we haven't gotten to it yet.
|
||||||
*/
|
*/
|
||||||
if (s->btps_next == NULL)
|
if (s->btps_next == NULL)
|
||||||
{
|
{
|
||||||
|
@ -657,8 +655,8 @@ _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is the rightmost page, so the ItemId array needs to be
|
* This is the rightmost page, so the ItemId array needs to be slid
|
||||||
* slid back one slot. Then we can dump out the page.
|
* back one slot. Then we can dump out the page.
|
||||||
*/
|
*/
|
||||||
_bt_slideleft(s->btps_page);
|
_bt_slideleft(s->btps_page);
|
||||||
_bt_blwritepage(wstate, s->btps_page, s->btps_blkno);
|
_bt_blwritepage(wstate, s->btps_page, s->btps_blkno);
|
||||||
|
@ -667,9 +665,9 @@ _bt_uppershutdown(BTWriteState *wstate, BTPageState *state)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* As the last step in the process, construct the metapage and make it
|
* As the last step in the process, construct the metapage and make it
|
||||||
* point to the new root (unless we had no data at all, in which case
|
* point to the new root (unless we had no data at all, in which case it's
|
||||||
* it's set to point to "P_NONE"). This changes the index to the
|
* set to point to "P_NONE"). This changes the index to the "valid" state
|
||||||
* "valid" state by filling in a valid magic number in the metapage.
|
* by filling in a valid magic number in the metapage.
|
||||||
*/
|
*/
|
||||||
metapage = (Page) palloc(BLCKSZ);
|
metapage = (Page) palloc(BLCKSZ);
|
||||||
_bt_initmetapage(metapage, rootblkno, rootlevel);
|
_bt_initmetapage(metapage, rootblkno, rootlevel);
|
||||||
|
@ -805,19 +803,19 @@ _bt_load(BTWriteState *wstate, BTSpool *btspool, BTSpool *btspool2)
|
||||||
_bt_uppershutdown(wstate, state);
|
_bt_uppershutdown(wstate, state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the index isn't temp, we must fsync it down to disk before it's
|
* If the index isn't temp, we must fsync it down to disk before it's safe
|
||||||
* safe to commit the transaction. (For a temp index we don't care
|
* to commit the transaction. (For a temp index we don't care since the
|
||||||
* since the index will be uninteresting after a crash anyway.)
|
* index will be uninteresting after a crash anyway.)
|
||||||
*
|
*
|
||||||
* It's obvious that we must do this when not WAL-logging the build. It's
|
* It's obvious that we must do this when not WAL-logging the build. It's
|
||||||
* less obvious that we have to do it even if we did WAL-log the index
|
* less obvious that we have to do it even if we did WAL-log the index
|
||||||
* pages. The reason is that since we're building outside shared
|
* pages. The reason is that since we're building outside shared buffers,
|
||||||
* buffers, a CHECKPOINT occurring during the build has no way to
|
* a CHECKPOINT occurring during the build has no way to flush the
|
||||||
* flush the previously written data to disk (indeed it won't know the
|
* previously written data to disk (indeed it won't know the index even
|
||||||
* index even exists). A crash later on would replay WAL from the
|
* exists). A crash later on would replay WAL from the checkpoint,
|
||||||
* checkpoint, therefore it wouldn't replay our earlier WAL entries.
|
* therefore it wouldn't replay our earlier WAL entries. If we do not
|
||||||
* If we do not fsync those pages here, they might still not be on
|
* fsync those pages here, they might still not be on disk when the crash
|
||||||
* disk when the crash occurs.
|
* occurs.
|
||||||
*/
|
*/
|
||||||
if (!wstate->index->rd_istemp)
|
if (!wstate->index->rd_istemp)
|
||||||
smgrimmedsync(wstate->index->rd_smgr);
|
smgrimmedsync(wstate->index->rd_smgr);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.63 2005/06/13 23:14:48 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtutils.c,v 1.64 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -48,8 +48,8 @@ _bt_mkscankey(Relation rel, IndexTuple itup)
|
||||||
bool null;
|
bool null;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can use the cached (default) support procs since no
|
* We can use the cached (default) support procs since no cross-type
|
||||||
* cross-type comparison can be needed.
|
* comparison can be needed.
|
||||||
*/
|
*/
|
||||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||||
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
arg = index_getattr(itup, i + 1, itupdesc, &null);
|
||||||
|
@ -93,8 +93,8 @@ _bt_mkscankey_nodata(Relation rel)
|
||||||
FmgrInfo *procinfo;
|
FmgrInfo *procinfo;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can use the cached (default) support procs since no
|
* We can use the cached (default) support procs since no cross-type
|
||||||
* cross-type comparison can be needed.
|
* comparison can be needed.
|
||||||
*/
|
*/
|
||||||
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
procinfo = index_getprocinfo(rel, i + 1, BTORDER_PROC);
|
||||||
ScanKeyEntryInitializeWithInfo(&skey[i],
|
ScanKeyEntryInitializeWithInfo(&skey[i],
|
||||||
|
@ -257,9 +257,9 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||||
if (numberOfKeys == 1)
|
if (numberOfKeys == 1)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* We don't use indices for 'A is null' and 'A is not null'
|
* We don't use indices for 'A is null' and 'A is not null' currently
|
||||||
* currently and 'A < = > <> NULL' will always fail - so qual is
|
* and 'A < = > <> NULL' will always fail - so qual is not OK if
|
||||||
* not OK if comparison value is NULL. - vadim 03/21/97
|
* comparison value is NULL. - vadim 03/21/97
|
||||||
*/
|
*/
|
||||||
if (cur->sk_flags & SK_ISNULL)
|
if (cur->sk_flags & SK_ISNULL)
|
||||||
so->qual_ok = false;
|
so->qual_ok = false;
|
||||||
|
@ -286,20 +286,20 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||||
/*
|
/*
|
||||||
* Initialize for processing of keys for attr 1.
|
* Initialize for processing of keys for attr 1.
|
||||||
*
|
*
|
||||||
* xform[i] points to the currently best scan key of strategy type i+1,
|
* xform[i] points to the currently best scan key of strategy type i+1, if
|
||||||
* if any is found with a default operator subtype; it is NULL if we
|
* any is found with a default operator subtype; it is NULL if we haven't
|
||||||
* haven't yet found such a key for this attr. Scan keys of
|
* yet found such a key for this attr. Scan keys of nondefault subtypes
|
||||||
* nondefault subtypes are transferred to the output with no
|
* are transferred to the output with no processing except for noting if
|
||||||
* processing except for noting if they are of "=" type.
|
* they are of "=" type.
|
||||||
*/
|
*/
|
||||||
attno = 1;
|
attno = 1;
|
||||||
memset(xform, 0, sizeof(xform));
|
memset(xform, 0, sizeof(xform));
|
||||||
hasOtherTypeEqual = false;
|
hasOtherTypeEqual = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Loop iterates from 0 to numberOfKeys inclusive; we use the last
|
* Loop iterates from 0 to numberOfKeys inclusive; we use the last pass to
|
||||||
* pass to handle after-last-key processing. Actual exit from the
|
* handle after-last-key processing. Actual exit from the loop is at the
|
||||||
* loop is at the "break" statement below.
|
* "break" statement below.
|
||||||
*/
|
*/
|
||||||
for (i = 0;; cur++, i++)
|
for (i = 0;; cur++, i++)
|
||||||
{
|
{
|
||||||
|
@ -319,8 +319,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we are at the end of the keys for a particular attr, finish
|
* If we are at the end of the keys for a particular attr, finish up
|
||||||
* up processing and emit the cleaned-up keys.
|
* processing and emit the cleaned-up keys.
|
||||||
*/
|
*/
|
||||||
if (i == numberOfKeys || cur->sk_attno != attno)
|
if (i == numberOfKeys || cur->sk_attno != attno)
|
||||||
{
|
{
|
||||||
|
@ -331,9 +331,9 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||||
elog(ERROR, "btree index keys must be ordered by attribute");
|
elog(ERROR, "btree index keys must be ordered by attribute");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If = has been specified, no other key will be used. In case
|
* If = has been specified, no other key will be used. In case of
|
||||||
* of key > 2 && key == 1 and so on we have to set qual_ok to
|
* key > 2 && key == 1 and so on we have to set qual_ok to false
|
||||||
* false before discarding the other keys.
|
* before discarding the other keys.
|
||||||
*/
|
*/
|
||||||
if (xform[BTEqualStrategyNumber - 1])
|
if (xform[BTEqualStrategyNumber - 1])
|
||||||
{
|
{
|
||||||
|
@ -411,8 +411,8 @@ _bt_preprocess_keys(IndexScanDesc scan)
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If all attrs before this one had "=", include these keys
|
* If all attrs before this one had "=", include these keys into
|
||||||
* into the required-keys count.
|
* the required-keys count.
|
||||||
*/
|
*/
|
||||||
if (priorNumberOfEqualCols == attno - 1)
|
if (priorNumberOfEqualCols == attno - 1)
|
||||||
so->numberOfRequiredKeys = new_numberOfKeys;
|
so->numberOfRequiredKeys = new_numberOfKeys;
|
||||||
|
@ -526,11 +526,11 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
|
||||||
if (isNull)
|
if (isNull)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Since NULLs are sorted after non-NULLs, we know we have
|
* Since NULLs are sorted after non-NULLs, we know we have reached
|
||||||
* reached the upper limit of the range of values for this
|
* the upper limit of the range of values for this index attr. On
|
||||||
* index attr. On a forward scan, we can stop if this qual is
|
* a forward scan, we can stop if this qual is one of the "must
|
||||||
* one of the "must match" subset. On a backward scan,
|
* match" subset. On a backward scan, however, we should keep
|
||||||
* however, we should keep going.
|
* going.
|
||||||
*/
|
*/
|
||||||
if (ikey < so->numberOfRequiredKeys &&
|
if (ikey < so->numberOfRequiredKeys &&
|
||||||
ScanDirectionIsForward(dir))
|
ScanDirectionIsForward(dir))
|
||||||
|
@ -547,24 +547,22 @@ _bt_checkkeys(IndexScanDesc scan, IndexTuple tuple,
|
||||||
if (!DatumGetBool(test))
|
if (!DatumGetBool(test))
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Tuple fails this qual. If it's a required qual, then we
|
* Tuple fails this qual. If it's a required qual, then we may be
|
||||||
* may be able to conclude no further tuples will pass,
|
* able to conclude no further tuples will pass, either. We have
|
||||||
* either. We have to look at the scan direction and the qual
|
* to look at the scan direction and the qual type.
|
||||||
* type.
|
|
||||||
*
|
*
|
||||||
* Note: the only case in which we would keep going after failing
|
* Note: the only case in which we would keep going after failing a
|
||||||
* a required qual is if there are partially-redundant quals
|
* required qual is if there are partially-redundant quals that
|
||||||
* that _bt_preprocess_keys() was unable to eliminate. For
|
* _bt_preprocess_keys() was unable to eliminate. For example,
|
||||||
* example, given "x > 4 AND x > 10" where both are cross-type
|
* given "x > 4 AND x > 10" where both are cross-type comparisons
|
||||||
* comparisons and so not removable, we might start the scan
|
* and so not removable, we might start the scan at the x = 4
|
||||||
* at the x = 4 boundary point. The "x > 10" condition will
|
* boundary point. The "x > 10" condition will fail until we pass
|
||||||
* fail until we pass x = 10, but we must not stop the scan on
|
* x = 10, but we must not stop the scan on its account.
|
||||||
* its account.
|
|
||||||
*
|
*
|
||||||
* Note: because we stop the scan as soon as any required
|
* Note: because we stop the scan as soon as any required equality
|
||||||
* equality qual fails, it is critical that equality quals be
|
* qual fails, it is critical that equality quals be used for the
|
||||||
* used for the initial positioning in _bt_first() when they
|
* initial positioning in _bt_first() when they are available. See
|
||||||
* are available. See comments in _bt_first().
|
* comments in _bt_first().
|
||||||
*/
|
*/
|
||||||
if (ikey < so->numberOfRequiredKeys)
|
if (ikey < so->numberOfRequiredKeys)
|
||||||
{
|
{
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.22 2005/06/06 17:01:22 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.23 2005/10/15 02:49:09 momjian Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
@ -136,8 +136,8 @@ _bt_restore_meta(Relation reln, XLogRecPtr lsn,
|
||||||
pageop->btpo_flags = BTP_META;
|
pageop->btpo_flags = BTP_META;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set pd_lower just past the end of the metadata. This is not
|
* Set pd_lower just past the end of the metadata. This is not essential
|
||||||
* essential but it makes the page look compressible to xlog.c.
|
* but it makes the page look compressible to xlog.c.
|
||||||
*/
|
*/
|
||||||
((PageHeader) metapg)->pd_lower =
|
((PageHeader) metapg)->pd_lower =
|
||||||
((char *) md + sizeof(BTMetaPageData)) - (char *) metapg;
|
((char *) md + sizeof(BTMetaPageData)) - (char *) metapg;
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue