monitoring sort activities

Поиск
Список
Период
Сортировка
От Satoshi Nagayasu
Тема monitoring sort activities
Дата
Msg-id 4334ED10.5060808@nttdata.co.jp
обсуждение исходный текст
Список pgsql-patches
Hi folks,

I've created a patch to get following TODO item.

> * %Add ability to monitor the use of temporary sort files

This patch provides one system view (pg_stat_sorts) and
one utility function (pg_stat_get_prev_sort_size).

> snaga=# SELECT * from pg_stat_sorts;
>  heap_all | index_all | datum_all | heap_tape | datum_tape | max_size
> ----------+-----------+-----------+-----------+------------+----------
>         4 |         6 |         0 |         4 |          0 | 26400000
> (1 row)
>
> snaga=# select aid from accounts where aid % 2 = 1 order by filler
desc limit 10;
>
> [...snip...]
>
> (10 rows)
>
> snaga=# SELECT pg_stat_get_prev_sort_size();
>  pg_stat_get_prev_sort_size
> ----------------------------
>                    13200000
> (1 row)

Yeah, I don't forget previous discussion with Tom. We also have to
monitor temp files, but I think these view and function will benefit
DBAs on performance tuning.

Any comments or suggestion?
--
NAGAYASU Satoshi <nagayasus@nttdata.co.jp>
diff -rc postgresql-8.1beta2.orig/src/backend/catalog/system_views.sql
postgresql-8.1beta2/src/backend/catalog/system_views.sql
*** postgresql-8.1beta2.orig/src/backend/catalog/system_views.sql    2005-09-24 11:29:38.000000000 +0900
--- postgresql-8.1beta2/src/backend/catalog/system_views.sql    2005-09-24 14:27:18.000000000 +0900
***************
*** 320,325 ****
--- 320,335 ----
      WHERE pg_stat_get_backend_dbid(S.backendid) = D.oid AND
              pg_stat_get_backend_userid(S.backendid) = U.oid;

+
+ CREATE VIEW pg_stat_sorts AS
+   SELECT pg_stat_get_sort_heap_all() as heap_all,
+          pg_stat_get_sort_index_all() as index_all,
+          pg_stat_get_sort_datum_all() as datum_all,
+          pg_stat_get_sort_heap_tape() as heap_tape,
+          pg_stat_get_sort_datum_tape() as datum_tape,
+          pg_stat_get_max_sort_size() as max_size;
+
+
  CREATE VIEW pg_stat_database AS
      SELECT
              D.oid AS datid,
diff -rc postgresql-8.1beta2.orig/src/backend/postmaster/pgstat.c postgresql-8.1beta2/src/backend/postmaster/pgstat.c
*** postgresql-8.1beta2.orig/src/backend/postmaster/pgstat.c    2005-09-24 11:29:39.000000000 +0900
--- postgresql-8.1beta2/src/backend/postmaster/pgstat.c    2005-09-24 14:42:09.000000000 +0900
***************
*** 120,125 ****
--- 120,132 ----

  static bool pgStatRunningInCollector = FALSE;

+ static long pgStatSortHeapAll   = 0;
+ static long pgStatSortIndexAll  = 0;
+ static long pgStatSortDatumAll  = 0;
+ static long pgStatSortHeapTape  = 0;
+ static long pgStatSortDatumTape = 0;
+ static Size pgStatSortMaxUsedSize = 0;
+
  /*
   * Place where backends store per-table info to be sent to the collector.
   * We store shared relations separately from non-shared ones, to be able to
***************
*** 823,828 ****
--- 830,843 ----
          return;
      }

+     elog(DEBUG1, "report: Sort statistics: [dbentry=%d]", MyDatabaseId);
+     elog(DEBUG1, "report: Sort statistics: heap(all)=%ld, index(all)=%ld, datum(all)=%ld",
+          pgStatSortHeapAll,pgStatSortIndexAll,pgStatSortDatumAll);
+     elog(DEBUG1, "report: Sort statistics: heap(tape)=%ld, datum(tape)=%ld",
+          pgStatSortHeapTape,pgStatSortDatumTape);
+     elog(DEBUG1, "report: Sort statistics: MaxSortSize=%ld",
+          pgStatSortMaxUsedSize);
+
      /*
       * For each message buffer used during the last query set the header
       * fields and send it out.
***************
*** 839,847 ****
--- 854,877 ----

          tsmsg->m_xact_commit = pgStatXactCommit;
          tsmsg->m_xact_rollback = pgStatXactRollback;
+
          pgStatXactCommit = 0;
          pgStatXactRollback = 0;

+         tsmsg->m_sort_heap_all   = pgStatSortHeapAll;
+         tsmsg->m_sort_index_all  = pgStatSortIndexAll;
+         tsmsg->m_sort_datum_all  = pgStatSortDatumAll;
+         tsmsg->m_sort_heap_tape  = pgStatSortHeapTape;
+         tsmsg->m_sort_datum_tape = pgStatSortDatumTape;
+         tsmsg->m_sort_max_used_size = pgStatSortMaxUsedSize;
+
+         pgStatSortHeapAll   = 0;
+         pgStatSortIndexAll  = 0;
+         pgStatSortDatumAll  = 0;
+         pgStatSortHeapTape  = 0;
+         pgStatSortDatumTape = 0;
+         pgStatSortMaxUsedSize = 0;
+
          pgstat_setheader(&tsmsg->m_hdr, PGSTAT_MTYPE_TABSTAT);
          tsmsg->m_databaseid = MyDatabaseId;
          pgstat_send(tsmsg, len);
***************
*** 2218,2223 ****
--- 2248,2260 ----
          result->destroy = 0;
          result->last_autovac_time = 0;

+         result->n_sort_heap_all   = 0;
+         result->n_sort_index_all  = 0;
+         result->n_sort_datum_all  = 0;
+         result->n_sort_heap_tape  = 0;
+         result->n_sort_datum_tape = 0;
+         result->sort_max_used_size = 0;
+
          memset(&hash_ctl, 0, sizeof(hash_ctl));
          hash_ctl.keysize = sizeof(Oid);
          hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
***************
*** 3050,3055 ****
--- 3087,3101 ----
      dbentry->n_xact_commit += (PgStat_Counter) (msg->m_xact_commit);
      dbentry->n_xact_rollback += (PgStat_Counter) (msg->m_xact_rollback);

+     dbentry->n_sort_heap_all   += (PgStat_Counter) (msg->m_sort_heap_all);
+     dbentry->n_sort_index_all  += (PgStat_Counter) (msg->m_sort_index_all);
+     dbentry->n_sort_datum_all  += (PgStat_Counter) (msg->m_sort_datum_all);
+     dbentry->n_sort_heap_tape  += (PgStat_Counter) (msg->m_sort_heap_tape);
+     dbentry->n_sort_datum_tape += (PgStat_Counter) (msg->m_sort_datum_tape);
+
+     if ( dbentry->sort_max_used_size < msg->m_sort_max_used_size )
+         dbentry->sort_max_used_size = (Size)msg->m_sort_max_used_size;
+
      /*
       * Process all table entries in the message.
       */
***************
*** 3229,3234 ****
--- 3275,3287 ----
      dbentry->n_blocks_hit = 0;
      dbentry->destroy = 0;

+     dbentry->n_sort_heap_all   = 0;
+     dbentry->n_sort_index_all  = 0;
+     dbentry->n_sort_datum_all  = 0;
+     dbentry->n_sort_heap_tape  = 0;
+     dbentry->n_sort_datum_tape = 0;
+     dbentry->sort_max_used_size = 0;
+
      memset(&hash_ctl, 0, sizeof(hash_ctl));
      hash_ctl.keysize = sizeof(Oid);
      hash_ctl.entrysize = sizeof(PgStat_StatTabEntry);
***************
*** 3238,3240 ****
--- 3291,3344 ----
                                    &hash_ctl,
                                    HASH_ELEM | HASH_FUNCTION);
  }
+
+
+ void
+ pgstat_count_sort_heap_all()
+ {
+     pgStatSortHeapAll++;
+
+     elog(DEBUG5, "pgstat_count_sort_heap_all(): %d", pgStatSortHeapAll);
+ }
+
+ void
+ pgstat_count_sort_index_all()
+ {
+     pgStatSortIndexAll++;
+
+     elog(DEBUG5, "pgstat_count_sort_index_all(): %d", pgStatSortIndexAll);
+ }
+
+ void
+ pgstat_count_sort_datum_all()
+ {
+     pgStatSortDatumAll++;
+
+     elog(DEBUG5, "pgstat_count_sort_datum_all(): %d", pgStatSortDatumAll);
+ }
+
+ void
+ pgstat_count_sort_heap_tape()
+ {
+     pgStatSortHeapTape++;
+
+     elog(DEBUG5, "pgstat_count_sort_heap_tape(): %d", pgStatSortHeapTape);
+ }
+
+ void
+ pgstat_count_sort_datum_tape()
+ {
+     pgStatSortDatumTape++;
+
+     elog(DEBUG5, "pgstat_count_sort_datum_tape(): %d", pgStatSortDatumTape);
+ }
+
+ void
+ pgstat_count_sort_max_used_size(Size size)
+ {
+     if ( size>pgStatSortMaxUsedSize )
+         pgStatSortMaxUsedSize = size;
+
+     elog(DEBUG5, "pgstat_count_sort_max_used_size(): %ld",
+          pgStatSortMaxUsedSize);
+ }
diff -rc postgresql-8.1beta2.orig/src/backend/utils/adt/pgstatfuncs.c
postgresql-8.1beta2/src/backend/utils/adt/pgstatfuncs.c
*** postgresql-8.1beta2.orig/src/backend/utils/adt/pgstatfuncs.c    2005-09-24 11:29:42.000000000 +0900
--- postgresql-8.1beta2/src/backend/utils/adt/pgstatfuncs.c    2005-09-24 14:36:27.000000000 +0900
***************
*** 53,58 ****
--- 53,81 ----
  extern Datum pg_stat_get_db_blocks_fetched(PG_FUNCTION_ARGS);
  extern Datum pg_stat_get_db_blocks_hit(PG_FUNCTION_ARGS);

+ typedef enum SORT_TYPE {
+     HEAP_ALL,
+     INDEX_ALL,
+     DATUM_ALL,
+     HEAP_TAPE,
+     DATUM_TAPE
+ } SORT_TYPE;
+
+ PG_FUNCTION_INFO_V1(pg_stat_get_sort_heap_all);
+ PG_FUNCTION_INFO_V1(pg_stat_get_sort_index_all);
+ PG_FUNCTION_INFO_V1(pg_stat_get_sort_datum_all);
+ PG_FUNCTION_INFO_V1(pg_stat_get_sort_heap_tape);
+ PG_FUNCTION_INFO_V1(pg_stat_get_sort_datum_tape);
+ PG_FUNCTION_INFO_V1(pg_stat_get_max_sort_size);
+ PG_FUNCTION_INFO_V1(pg_stat_get_prev_sort_size);
+
+ extern Datum pg_stat_get_sort_heap_all(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_sort_index_all(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_sort_datum_all(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_sort_heap_tape(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_sort_datum_tape(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_max_sort_size(PG_FUNCTION_ARGS);
+ extern Datum pg_stat_get_prev_sort_size(PG_FUNCTION_ARGS);

  Datum
  pg_stat_get_numscans(PG_FUNCTION_ARGS)
***************
*** 562,564 ****
--- 585,693 ----

      PG_RETURN_INT64(result);
  }
+
+
+ static int64
+ get_sort_stat_internal(SORT_TYPE type)
+ {
+     PgStat_StatDBEntry *dbentry;
+     int64           result = 0;
+
+     Oid dbid = MyDatabaseId;
+
+     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+         result = -1;
+     else
+         switch (type)
+         {
+             case HEAP_ALL:
+                 result = (int64) (dbentry->n_sort_heap_all);
+                 break;
+             case INDEX_ALL:
+                 result = (int64) (dbentry->n_sort_index_all);
+                 break;
+             case DATUM_ALL:
+                 result = (int64) (dbentry->n_sort_datum_all);
+                 break;
+             case HEAP_TAPE:
+                 result = (int64) (dbentry->n_sort_heap_tape);
+                 break;
+             case DATUM_TAPE:
+                 result = (int64) (dbentry->n_sort_datum_tape);
+                 break;
+             default:
+                 elog(ERROR, "get_sort_stat_internal: unexpected type.");
+                 break;
+         }
+
+     if ( dbentry )
+     {
+             elog(DEBUG5, "get_sort_stat_internal(): [dbentry=%d]", dbentry->databaseid);
+             elog(DEBUG5, "get_sort_stat_internal(): heap(all)=%ld, index(all)=%ld, datum(all)=%ld",
+                  dbentry->n_sort_heap_all,
+                  dbentry->n_sort_index_all,
+                  dbentry->n_sort_datum_all);
+             elog(DEBUG5, "get_sort_stat_internal(): heap(tape)=%ld, datum(tape)=%ld",
+                  dbentry->n_sort_heap_tape,
+                  dbentry->n_sort_datum_tape);
+             elog(DEBUG5, "get_sort_stat_internal(): MaxSortSize=%ld",
+                  dbentry->sort_max_used_size);
+     }
+
+     return result;
+ }
+
+
+ Datum
+ pg_stat_get_sort_heap_all(PG_FUNCTION_ARGS)
+ {
+     PG_RETURN_INT64(get_sort_stat_internal(HEAP_ALL));
+ }
+
+ Datum
+ pg_stat_get_sort_index_all(PG_FUNCTION_ARGS)
+ {
+     PG_RETURN_INT64(get_sort_stat_internal(INDEX_ALL));
+ }
+
+ Datum
+ pg_stat_get_sort_datum_all(PG_FUNCTION_ARGS)
+ {
+     PG_RETURN_INT64(get_sort_stat_internal(DATUM_ALL));
+ }
+
+ Datum
+ pg_stat_get_sort_heap_tape(PG_FUNCTION_ARGS)
+ {
+     PG_RETURN_INT64(get_sort_stat_internal(HEAP_TAPE));
+ }
+
+ Datum
+ pg_stat_get_sort_datum_tape(PG_FUNCTION_ARGS)
+ {
+     PG_RETURN_INT64(get_sort_stat_internal(DATUM_TAPE));
+ }
+
+ Datum
+ pg_stat_get_max_sort_size(PG_FUNCTION_ARGS)
+ {
+     PgStat_StatDBEntry *dbentry;
+     Oid dbid;
+     int64           result;
+
+ //    dbid = PG_GETARG_OID(0);
+     dbid = MyDatabaseId;
+
+     if ((dbentry = pgstat_fetch_stat_dbentry(dbid)) == NULL)
+         result = -1;
+     else
+         result = (int64) (dbentry->sort_max_used_size);
+
+     PG_RETURN_INT64(result);
+ }
+
+ Datum
+ pg_stat_get_prev_sort_size(PG_FUNCTION_ARGS)
+ {
+     PG_RETURN_INT64(tuplesort_get_prev_size());
+ }
diff -rc postgresql-8.1beta2.orig/src/backend/utils/sort/tuplesort.c
postgresql-8.1beta2/src/backend/utils/sort/tuplesort.c
*** postgresql-8.1beta2.orig/src/backend/utils/sort/tuplesort.c    2005-09-24 11:29:46.000000000 +0900
--- postgresql-8.1beta2/src/backend/utils/sort/tuplesort.c    2005-09-24 14:35:27.000000000 +0900
***************
*** 283,288 ****
--- 283,290 ----
      /* we need typelen and byval in order to know how to copy the Datums. */
      int            datumTypeLen;
      bool        datumTypeByVal;
+
+     Size        usedSize;
  };

  #define COMPARETUP(state,a,b)    ((*(state)->comparetup) (state, a, b))
***************
*** 395,400 ****
--- 397,404 ----
  static Tuplesortstate *qsort_tuplesortstate;


+ static Size prevSortSize = 0;
+
  /*
   *        tuplesort_begin_xxx
   *
***************
*** 442,447 ****
--- 446,453 ----
      state->result_tape = -1;    /* flag that result tape has not been
                                   * formed */

+     state->usedSize = 0;
+
      return state;
  }

***************
*** 489,494 ****
--- 495,502 ----
                      (Datum) 0);
      }

+     pgstat_count_sort_heap_all();
+
      return state;
  }

***************
*** 509,514 ****
--- 517,524 ----
      state->indexScanKey = _bt_mkscankey_nodata(indexRel);
      state->enforceUnique = enforceUnique;

+     pgstat_count_sort_index_all();
+
      return state;
  }

***************
*** 540,545 ****
--- 550,557 ----
      state->datumTypeLen = typlen;
      state->datumTypeByVal = typbyval;

+     pgstat_count_sort_datum_all();
+
      return state;
  }

***************
*** 553,558 ****
--- 565,577 ----
  {
      int            i;

+     pgstat_count_sort_max_used_size(state->usedSize);
+
+     elog(DEBUG5, "tuplesort_end: usedSize=%ld, tape=%d",
+          state->usedSize, (state->tapeset ? 1 : 0));
+
+     prevSortSize = state->usedSize;
+
      if (state->tapeset)
          LogicalTapeSetClose(state->tapeset);
      if (state->memtuples)
***************
*** 1027,1032 ****
--- 1046,1057 ----
      state->Level = 1;
      state->destTape = 0;

+     /* If not a datum sort, it's a heap sort  */
+     if ( state->datumType == InvalidOid )
+         pgstat_count_sort_heap_tape();
+     else
+         pgstat_count_sort_datum_tape();
+
      state->status = TSS_BUILDRUNS;
  }

***************
*** 1952,1957 ****
--- 1977,1983 ----

      tuple = heap_copytuple(tuple);
      USEMEM(state, GetMemoryChunkSpace(tuple));
+     state->usedSize += GetMemoryChunkSpace(tuple);
      return (void *) tuple;
  }

***************
*** 2111,2116 ****
--- 2137,2143 ----

      newtuple = (IndexTuple) palloc(tuplen);
      USEMEM(state, GetMemoryChunkSpace(newtuple));
+     state->usedSize += GetMemoryChunkSpace(newtuple);

      memcpy(newtuple, tuple, tuplen);

***************
*** 2228,2230 ****
--- 2255,2264 ----
                                       MAXALIGN(sizeof(DatumTuple)));
      return (void *) tuple;
  }
+
+ Size
+ tuplesort_get_prev_size()
+ {
+     return prevSortSize;
+ }
+
diff -rc postgresql-8.1beta2.orig/src/include/catalog/pg_proc.h postgresql-8.1beta2/src/include/catalog/pg_proc.h
*** postgresql-8.1beta2.orig/src/include/catalog/pg_proc.h    2005-09-24 11:29:48.000000000 +0900
--- postgresql-8.1beta2/src/include/catalog/pg_proc.h    2005-09-24 14:32:59.000000000 +0900
***************
*** 2863,2868 ****
--- 2863,2883 ----
  DATA(insert OID = 1945 (  pg_stat_get_db_blocks_hit        PGNSP PGUID 12 f f t f s 1 20 "26" _null_ _null_ _null_
pg_stat_get_db_blocks_hit- _null_ )); 
  DESCR("Statistics: Blocks found in cache for database");

+ DATA(insert OID = 1971 (  pg_stat_get_sort_heap_all PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_sort_heap_all- _null_ )); 
+ DESCR("Statistics: pg_stat_get_sort_heap_all");
+ DATA(insert OID = 1972 (  pg_stat_get_sort_index_all PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_sort_index_all- _null_ )); 
+ DESCR("Statistics: pg_stat_get_sort_index_all");
+ DATA(insert OID = 1973 (  pg_stat_get_sort_datum_all PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_sort_datum_all- _null_ )); 
+ DESCR("Statistics: pg_stat_get_sort_datum_all");
+ DATA(insert OID = 1974 (  pg_stat_get_sort_heap_tape PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_sort_heap_tape- _null_ )); 
+ DESCR("Statistics: pg_stat_get_sort_heap_tape");
+ DATA(insert OID = 1975 (  pg_stat_get_sort_datum_tape PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_sort_datum_tape- _null_ )); 
+ DESCR("Statistics: pg_stat_get_sort_datum_tape");
+ DATA(insert OID = 1976 (  pg_stat_get_max_sort_size PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_max_sort_size- _null_ )); 
+ DESCR("Statistics: pg_stat_get_prev_sort_size");
+ DATA(insert OID = 1977 (  pg_stat_get_prev_sort_size PGNSP PGUID 12 f f t f s 0 20 "" _null_ _null_ _null_
pg_stat_get_prev_sort_size- _null_ )); 
+ DESCR("Statistics: pg_stat_get_prev_sort_size");
+
  DATA(insert OID = 1946 (  encode                        PGNSP PGUID 12 f f t f i 2 25 "17 25" _null_ _null_ _null_
binary_encode- _null_ )); 
  DESCR("Convert bytea value into some ascii-only text string");
  DATA(insert OID = 1947 (  decode                        PGNSP PGUID 12 f f t f i 2 17 "25 25" _null_ _null_ _null_
binary_decode- _null_ )); 
diff -rc postgresql-8.1beta2.orig/src/include/pgstat.h postgresql-8.1beta2/src/include/pgstat.h
*** postgresql-8.1beta2.orig/src/include/pgstat.h    2005-09-24 11:29:48.000000000 +0900
--- postgresql-8.1beta2/src/include/pgstat.h    2005-09-24 13:49:38.000000000 +0900
***************
*** 189,194 ****
--- 189,203 ----
      int            m_nentries;
      int            m_xact_commit;
      int            m_xact_rollback;
+
+     int            m_sort_heap_all;
+     int            m_sort_index_all;
+     int            m_sort_datum_all;
+     int            m_sort_heap_tape;
+     int            m_sort_datum_tape;
+
+     Size        m_sort_max_used_size;
+
      PgStat_TableEntry m_entry[PGSTAT_NUM_TABENTRIES];
  } PgStat_MsgTabstat;

***************
*** 276,281 ****
--- 285,299 ----
      PgStat_Counter n_xact_rollback;
      PgStat_Counter n_blocks_fetched;
      PgStat_Counter n_blocks_hit;
+
+     PgStat_Counter n_sort_heap_all;
+     PgStat_Counter n_sort_index_all;
+     PgStat_Counter n_sort_datum_all;
+     PgStat_Counter n_sort_heap_tape;
+     PgStat_Counter n_sort_datum_tape;
+
+     Size           sort_max_used_size;
+
      int            destroy;
      TimestampTz    last_autovac_time;
  } PgStat_StatDBEntry;
***************
*** 492,495 ****
--- 510,521 ----
  extern PgStat_StatBeEntry *pgstat_fetch_stat_beentry(int beid);
  extern int    pgstat_fetch_stat_numbackends(void);

+
+ extern void pgstat_count_sort_heap_all(void);
+ extern void pgstat_count_sort_index_all(void);
+ extern void pgstat_count_sort_datum_all(void);
+ extern void pgstat_count_sort_heap_tape(void);
+ extern void pgstat_count_sort_datum_tape(void);
+ extern void pgstat_count_sort_max_used_size(Size size);
+
  #endif   /* PGSTAT_H */
diff -rc postgresql-8.1beta2.orig/src/include/utils/tuplesort.h postgresql-8.1beta2/src/include/utils/tuplesort.h
*** postgresql-8.1beta2.orig/src/include/utils/tuplesort.h    2005-09-24 11:29:48.000000000 +0900
--- postgresql-8.1beta2/src/include/utils/tuplesort.h    2005-09-24 14:36:07.000000000 +0900
***************
*** 102,105 ****
--- 102,107 ----
                    Datum datum1, bool isNull1,
                    Datum datum2, bool isNull2);

+ extern Size tuplesort_get_prev_size();
+
  #endif   /* TUPLESORT_H */

В списке pgsql-patches по дате отправления:

Предыдущее
От: Michael Fuhr
Дата:
Сообщение: Re: PL/Python error checking
Следующее
От: Tom Lane
Дата:
Сообщение: Re: [HACKERS] Proposed patch to clean up signed-ness warnings