Обсуждение: Re: Tuple too big

Поиск
Список
Период
Сортировка

Re: Tuple too big

От
Bruce Momjian
Дата:
> I've encountered a strange behavior of the VACUUM ANALYZE command.
> It seems that this command works only if the size of a text field
> does not exceed approximately 4050 bytes! So the real limit on 
> tuple size is a half of the max tuple size. I've checked this effect
> on Postgres 6.4.2 (Sparc Solaris 2.5.1) and Postgres 6.5 (SUSE 6.1 
> Linux, kernel 2.2.5). Is this a bug or known feature?
> The python script used to reproduce this problem and results for 
> v6.4.2 and v6.5 are follows.
> size= 4059
> size= 4060
> size= 4061
> size= 4062
> size= 4063
> size= 4064
> size= 4065
> ERROR:  Tuple is too big: size 8188

I have always suspected these default values where wrong, but no one
reported it as a bug.

Here is a patch for 6.5 which will prevent the creation of these too big
tuples in certain cases.  Seems we should also check for max length at
the time we create the table, but it doesn't look like there is any code
to do that yet.

I am not going to apply this to 6.5.1 because it may have some unknown
side-affects.

--  Bruce Momjian                        |  http://www.op.net/~candle maillist@candle.pha.pa.us            |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026
 


Re: [HACKERS] Re: Tuple too big

От
Bruce Momjian
Дата:
> Here is a patch for 6.5 which will prevent the creation of these too big
> tuples in certain cases.  Seems we should also check for max length at
> the time we create the table, but it doesn't look like there is any code
> to do that yet.
> 
> I am not going to apply this to 6.5.1 because it may have some unknown
> side-affects.
> 

On second thought, the patch looks harmless, so I am going to apply it. 
It is better than what is currently there.

--  Bruce Momjian                        |  http://www.op.net/~candle maillist@candle.pha.pa.us            |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026
 


Re: [HACKERS] Re: Tuple too big

От
Bruce Momjian
Дата:
> I have always suspected these default values where wrong, but no one
> reported it as a bug.
> 
> Here is a patch for 6.5 which will prevent the creation of these too big
> tuples in certain cases.  Seems we should also check for max length at
> the time we create the table, but it doesn't look like there is any code
> to do that yet.
> 
> I am not going to apply this to 6.5.1 because it may have some unknown
> side-affects.

Oops, forgot the patch.  If people want this in 6.5.1, let me know.  I
am going to try and add real tuple check in the places that need it.

---------------------------------------------------------------------------


? src/Makefile.custom
? src/config.log
? src/log
? src/config.cache
? src/config.status
? src/GNUmakefile
? src/Makefile.global
? src/backend/fmgr.h
? src/backend/parse.h
? src/backend/postgres
? src/backend/global1.bki.source
? src/backend/local1_template1.bki.source
? src/backend/global1.description
? src/backend/local1_template1.description
? src/backend/bootstrap/bootparse.c
? src/backend/bootstrap/bootstrap_tokens.h
? src/backend/bootstrap/bootscanner.c
? src/backend/catalog/genbki.sh
? src/backend/catalog/global1.bki.source
? src/backend/catalog/global1.description
? src/backend/catalog/local1_template1.bki.source
? src/backend/catalog/local1_template1.description
? src/backend/port/Makefile
? src/backend/utils/Gen_fmgrtab.sh
? src/backend/utils/fmgr.h
? src/backend/utils/fmgrtab.c
? src/bin/cleardbdir/cleardbdir
? src/bin/createdb/createdb
? src/bin/createlang/createlang
? src/bin/createuser/createuser
? src/bin/destroydb/destroydb
? src/bin/destroylang/destroylang
? src/bin/destroyuser/destroyuser
? src/bin/initdb/initdb
? src/bin/initlocation/initlocation
? src/bin/ipcclean/ipcclean
? src/bin/pg_dump/Makefile
? src/bin/pg_dump/pg_dump
? src/bin/pg_id/pg_id
? src/bin/pg_passwd/pg_passwd
? src/bin/pg_version/Makefile
? src/bin/pg_version/pg_version
? src/bin/pgtclsh/mkMakefile.tcldefs.sh
? src/bin/pgtclsh/mkMakefile.tkdefs.sh
? src/bin/pgtclsh/Makefile.tkdefs
? src/bin/pgtclsh/Makefile.tcldefs
? src/bin/pgtclsh/pgtclsh
? src/bin/pgtclsh/pgtksh
? src/bin/psql/Makefile
? src/bin/psql/psql
? src/include/version.h
? src/include/config.h
? src/interfaces/ecpg/lib/Makefile
? src/interfaces/ecpg/lib/libecpg.so.3.0.0
? src/interfaces/ecpg/preproc/ecpg
? src/interfaces/libpgtcl/Makefile
? src/interfaces/libpgtcl/libpgtcl.so.2.0
? src/interfaces/libpq/Makefile
? src/interfaces/libpq/libpq.so.2.0
? src/interfaces/libpq++/Makefile
? src/interfaces/libpq++/libpq++.so.3.0
? src/interfaces/odbc/GNUmakefile
? src/interfaces/odbc/Makefile.global
? src/lextest/lex.yy.c
? src/lextest/lextest
? src/pl/plpgsql/src/Makefile
? src/pl/plpgsql/src/mklang.sql
? src/pl/plpgsql/src/pl_gram.c
? src/pl/plpgsql/src/pl.tab.h
? src/pl/plpgsql/src/pl_scan.c
? src/pl/plpgsql/src/libplpgsql.so.1.0
? src/pl/tcl/mkMakefile.tcldefs.sh
? src/pl/tcl/Makefile.tcldefs
? src/template/linux_m68k
Index: src/backend/access/heap/stats.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/access/heap/stats.c,v
retrieving revision 1.15
diff -c -r1.15 stats.c
*** src/backend/access/heap/stats.c    1999/02/13 23:14:25    1.15
--- src/backend/access/heap/stats.c    1999/07/02 23:34:45
***************
*** 16,21 ****
--- 16,22 ----  */  #include <stdio.h>
+ #include <time.h>  #include <postgres.h> 
Index: src/backend/catalog/index.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/catalog/index.c,v
retrieving revision 1.79
diff -c -r1.79 index.c
*** src/backend/catalog/index.c    1999/06/19 04:54:11    1.79
--- src/backend/catalog/index.c    1999/07/02 23:34:47
***************
*** 20,25 ****
--- 20,26 ---- #include "postgres.h"  #include "access/genam.h"
+ #include "access/htup.h" #include "access/heapam.h" #include "access/istrat.h" #include "access/xact.h"
***************
*** 56,62 **** /*  * macros used in guessing how many tuples are on a page.  */
! #define AVG_TUPLE_SIZE 8 #define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))  /* non-export function
prototypes*/
 
--- 57,63 ---- /*  * macros used in guessing how many tuples are on a page.  */
! #define AVG_TUPLE_SIZE MinTupleSize #define NTUPLES_PER_PAGE(natts) (BLCKSZ/((natts)*AVG_TUPLE_SIZE))  /* non-export
functionprototypes */
 
Index: src/backend/commands/copy.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/commands/copy.c,v
retrieving revision 1.80
diff -c -r1.80 copy.c
*** src/backend/commands/copy.c    1999/06/12 20:41:25    1.80
--- src/backend/commands/copy.c    1999/07/02 23:34:52
***************
*** 1073,1079 ****     } } 
! #define EXT_ATTLEN 5*BLCKSZ  /*    returns 1 is c is in s
--- 1073,1079 ----     } } 
! #define EXT_ATTLEN    (5 * BLCKSZ)  /*    returns 1 is c is in s
Index: src/backend/commands/vacuum.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/commands/vacuum.c,v
retrieving revision 1.109
diff -c -r1.109 vacuum.c
*** src/backend/commands/vacuum.c    1999/06/11 09:35:08    1.109
--- src/backend/commands/vacuum.c    1999/07/02 23:35:02
***************
*** 624,630 ****                 empty_end_pages;     Size        free_size,                 usable_free_size;
!     Size        min_tlen = MAXTUPLEN;     Size        max_tlen = 0;     int32        i;     struct rusage ru0,
--- 624,630 ----                 empty_end_pages;     Size        free_size,                 usable_free_size;
!     Size        min_tlen = MaxTupleSize;     Size        max_tlen = 0;     int32        i;     struct rusage ru0,
Index: src/backend/optimizer/path/_deadcode/xfunc.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/optimizer/path/_deadcode/xfunc.c,v
retrieving revision 1.4
diff -c -r1.4 xfunc.c
*** src/backend/optimizer/path/_deadcode/xfunc.c    1999/05/25 22:41:36    1.4
--- src/backend/optimizer/path/_deadcode/xfunc.c    1999/07/02 23:35:08
***************
*** 20,25 ****
--- 20,26 ----  #include "postgres.h" 
+ #include "access/htup.h" #include "access/heapam.h" #include "catalog/pg_language.h" #include "catalog/pg_proc.h"
***************
*** 1094,1100 ****     RelOptInfo    outerrel = get_parent((Path) get_outerjoinpath(joinnode));     RelOptInfo
innerrel= get_parent((Path) get_innerjoinpath(joinnode));     Count        outerwidth = get_width(outerrel);
 
!     Count        outers_per_page = ceil(BLCKSZ / (outerwidth + sizeof(HeapTupleData)));      if (IsA(joinnode,
HashPath))    {
 
--- 1095,1101 ----     RelOptInfo    outerrel = get_parent((Path) get_outerjoinpath(joinnode));     RelOptInfo
innerrel= get_parent((Path) get_innerjoinpath(joinnode));     Count        outerwidth = get_width(outerrel);
 
!     Count        outers_per_page = ceil(BLCKSZ / (outerwidth + MinTupleSize));      if (IsA(joinnode, HashPath))
{
Index: src/backend/parser/gram.y
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.84
diff -c -r2.84 gram.y
*** src/backend/parser/gram.y    1999/06/07 14:28:25    2.84
--- src/backend/parser/gram.y    1999/07/02 23:35:24
***************
*** 36,41 ****
--- 36,42 ---- #include <ctype.h>  #include "postgres.h"
+ #include "access/htup.h" #include "nodes/parsenodes.h" #include "nodes/print.h" #include "parser/gramparse.h"
***************
*** 3384,3391 ****                      if ($3 < 1)                         elog(ERROR,"length for '%s' type must be at
least1",$1);
 
!                     else if ($3 > BLCKSZ - 128)
!                         elog(ERROR,"length for type '%s' cannot exceed %d",$1, BLCKSZ-128);                      /*
weactually implement this sort of like a varlen, so                      * the first 4 bytes is the length. (the
difference
--- 3385,3393 ----                      if ($3 < 1)                         elog(ERROR,"length for '%s' type must be at
least1",$1);
 
!                     else if ($3 > MaxTupleSize)
!                         elog(ERROR,"length for type '%s' cannot exceed %d",$1,
!                             MaxTupleSize);                      /* we actually implement this sort of like a varlen,
so                     * the first 4 bytes is the length. (the difference
 
Index: src/backend/storage/page/bufpage.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/storage/page/bufpage.c,v
retrieving revision 1.22
diff -c -r1.22 bufpage.c
*** src/backend/storage/page/bufpage.c    1999/05/25 16:11:25    1.22
--- src/backend/storage/page/bufpage.c    1999/07/02 23:35:28
***************
*** 45,51 ****      Assert(pageSize == BLCKSZ);     Assert(pageSize >
!            specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData));      specialSize = DOUBLEALIGN(specialSize); 
--- 45,51 ----      Assert(pageSize == BLCKSZ);     Assert(pageSize >
!              specialSize + sizeof(PageHeaderData) - sizeof(ItemIdData));      specialSize = DOUBLEALIGN(specialSize);

Index: src/backend/utils/adt/varchar.c
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/backend/utils/adt/varchar.c,v
retrieving revision 1.46
diff -c -r1.46 varchar.c
*** src/backend/utils/adt/varchar.c    1999/05/25 16:12:21    1.46
--- src/backend/utils/adt/varchar.c    1999/07/02 23:35:29
***************
*** 14,19 ****
--- 14,20 ---- #include <stdio.h>                /* for sprintf() */ #include <string.h> #include "postgres.h"
+ #include "access/htup.h" #include "utils/array.h" #include "utils/builtins.h" #include "catalog/pg_type.h"
***************
*** 81,88 ****     else         len = atttypmod - VARHDRSZ; 
!     if (len > BLCKSZ - 128)
!         elog(ERROR, "bpcharin: length of char() must be less than %d", BLCKSZ - 128);      result = (char *)
palloc(atttypmod);    VARSIZE(result) = atttypmod;
 
--- 82,90 ----     else         len = atttypmod - VARHDRSZ; 
!     if (len > MaxTupleSize)
!         elog(ERROR, "bpcharin: length of char() must be less than %d",
!                 MaxTupleSize);      result = (char *) palloc(atttypmod);     VARSIZE(result) = atttypmod;
***************
*** 151,158 ****      rlen = len - VARHDRSZ; 
!     if (rlen > BLCKSZ - 128)
!         elog(ERROR, "bpchar: length of char() must be less than %d", BLCKSZ - 128);  #ifdef STRINGDEBUG
printf("bpchar-convert string length %d (%d) ->%d (%d)\n",
 
--- 153,161 ----      rlen = len - VARHDRSZ; 
!     if (rlen > MaxTupleSize)
!         elog(ERROR, "bpchar: length of char() must be less than %d",
!             MaxTupleSize);  #ifdef STRINGDEBUG     printf("bpchar- convert string length %d (%d) ->%d (%d)\n",
***************
*** 332,339 ****     if (atttypmod != -1 && len > atttypmod)         len = atttypmod;        /* clip the string at max
length*/ 
 
!     if (len > BLCKSZ - 128)
!         elog(ERROR, "varcharin: length of char() must be less than %d", BLCKSZ - 128);      result = (char *)
palloc(len);    VARSIZE(result) = len;
 
--- 335,343 ----     if (atttypmod != -1 && len > atttypmod)         len = atttypmod;        /* clip the string at max
length*/ 
 
!     if (len > MaxTupleSize)
!         elog(ERROR, "varcharin: length of char() must be less than %d",
!                 MaxTupleSize);      result = (char *) palloc(len);     VARSIZE(result) = len;
***************
*** 403,410 ****     len = slen - VARHDRSZ; #endif 
!     if (len > BLCKSZ - 128)
!         elog(ERROR, "varchar: length of varchar() must be less than BLCKSZ-128");      result = (char *)
palloc(slen);    VARSIZE(result) = slen;
 
--- 407,415 ----     len = slen - VARHDRSZ; #endif 
!     if (len > MaxTupleSize)
!         elog(ERROR, "varchar: length of varchar() must be less than %d",
!             MaxTupleSize);      result = (char *) palloc(slen);     VARSIZE(result) = slen;
Index: src/include/access/htup.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/access/htup.h,v
retrieving revision 1.16
diff -c -r1.16 htup.h
*** src/include/access/htup.h    1999/05/25 22:42:32    1.16
--- src/include/access/htup.h    1999/07/02 23:35:34
***************
*** 13,19 **** #ifndef HTUP_H #define HTUP_H 
! #include <utils/nabstime.h> #include <storage/itemptr.h>  #define MinHeapTupleBitmapSize    32        /* 8 * 4 */
--- 13,19 ---- #ifndef HTUP_H #define HTUP_H 
! #include <storage/bufpage.h> #include <storage/itemptr.h>  #define MinHeapTupleBitmapSize    32        /* 8 * 4 */
***************
*** 51,56 ****
--- 51,61 ---- } HeapTupleHeaderData;  typedef HeapTupleHeaderData *HeapTupleHeader;
+ 
+ #define MinTupleSize    (sizeof (PageHeaderData) + \
+                          sizeof(HeapTupleHeaderData) + sizeof(int4))
+ 
+ #define MaxTupleSize    (BLCKSZ/2 - MinTupleSize)  #define SelfItemPointerAttributeNumber            (-1) #define
ObjectIdAttributeNumber                   (-2)
 
Index: src/include/storage/bufpage.h
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/include/storage/bufpage.h,v
retrieving revision 1.22
diff -c -r1.22 bufpage.h
*** src/include/storage/bufpage.h    1999/05/25 16:14:40    1.22
--- src/include/storage/bufpage.h    1999/07/02 23:35:36
***************
*** 133,150 ****     OverwritePageManagerMode } PageManagerMode; 
- /* ----------------
-  *        misc support macros
-  * ----------------
-  */
- 
- /*
-  * XXX this is wrong -- ignores padding/alignment, variable page size,
-  * AM-specific opaque space at the end of the page (as in btrees), ...
-  * however, it at least serves as an upper bound for heap pages.
-  */
- #define MAXTUPLEN        (BLCKSZ - sizeof (PageHeaderData))
-  /* ----------------------------------------------------------------  *                        page support macros  *
----------------------------------------------------------------
--- 133,138 ----
Index: src/interfaces/ecpg/preproc/preproc.y
===================================================================
RCS file: /usr/local/cvsroot/pgsql/src/interfaces/ecpg/preproc/preproc.y,v
retrieving revision 1.57
diff -c -r1.57 preproc.y
*** src/interfaces/ecpg/preproc/preproc.y    1999/06/16 18:25:50    1.57
--- src/interfaces/ecpg/preproc/preproc.y    1999/07/02 23:35:52
***************
*** 3,8 ****
--- 3,11 ---- #include <stdio.h> #include <string.h> #include <stdlib.h>
+ 
+ #include "postgres.h"
+ #include "access/htup.h" #include "catalog/catname.h" #include "utils/numeric.h" 
***************
*** 3351,3358 ****                         sprintf(errortext, "length for '%s' type must be at least 1",$1);
            yyerror(errortext);                     }
 
!                     else if (atol($3) > BLCKSZ - 128) {
!                         sprintf(errortext, "length for type '%s' cannot exceed %d",$1,BLCKSZ - 128);
      yyerror(errortext);                     } 
 
--- 3354,3361 ----                         sprintf(errortext, "length for '%s' type must be at least 1",$1);
            yyerror(errortext);                     }
 
!                     else if (atol($3) > MaxTupleSize) {
!                         sprintf(errortext, "length for type '%s' cannot exceed %d",$1,MaxTupleSize);
      yyerror(errortext);                     } 
 


--  Bruce Momjian                        |  http://www.op.net/~candle maillist@candle.pha.pa.us            |  (610)
853-3000+  If your life is a hard drive,     |  830 Blythe Avenue +  Christ can be your backup.        |  Drexel Hill,
Pennsylvania19026