text: -- predictability
  SET synchronous_commit = on;
  
  DROP TABLE IF EXISTS xpto;
  
  SELECT 'init' FROM pg_create_logical_replication_slot('regression_slot', 'test_decoding');
  
  CREATE SEQUENCE xpto_rand_seq START 79 INCREMENT 1499; -- portable "random"
  CREATE TABLE xpto (
      id serial primary key,
      toasted_col1 text,
      rand1 float8 DEFAULT nextval('xpto_rand_seq'),
      toasted_col2 text,
      rand2 float8 DEFAULT nextval('xpto_rand_seq')
  );
  
  -- uncompressed external toast data
  INSERT INTO xpto (toasted_col1, toasted_col2) SELECT string_agg(g.i::text, ''), string_agg((g.i*2)::text, '') FROM generate_series(1, 2000) g(i);
  
  -- compressed external toast data
  INSERT INTO xpto (toasted_col2) SELECT repeat(string_agg(to_char(g.i, 'FM0000'), ''), 50) FROM generate_series(1, 500) g(i);
  
  -- update of existing column
  UPDATE xpto SET toasted_col1 = (SELECT string_agg(g.i::text, '') FROM generate_series(1, 2000) g(i)) WHERE id = 1;
  
  UPDATE xpto SET rand1 = 123.456 WHERE id = 1;
  
  -- updating external via INSERT ... ON CONFLICT DO UPDATE
  INSERT INTO xpto(id, toasted_col2) VALUES (2, 'toasted2-upsert')
  ON CONFLICT (id)
  DO UPDATE SET toasted_col2 = EXCLUDED.toasted_col2 || xpto.toasted_col2;
  
  DELETE FROM xpto WHERE id = 1;
  
  DROP TABLE IF EXISTS toasted_key;
  CREATE TABLE toasted_key (
      id serial,
      toasted_key text PRIMARY KEY,
      toasted_col1 text,
      toasted_col2 text
  );
  
  ALTER TABLE toasted_key ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
  ALTER TABLE toasted_key ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
  
  INSERT INTO toasted_key(toasted_key, toasted_col1) VALUES(repeat('1234567890', 200), repeat('9876543210', 200));
  
  -- test update of a toasted key without changing it
  UPDATE toasted_key SET toasted_col2 = toasted_col1;
  -- test update of a toasted key, changing it
  UPDATE toasted_key SET toasted_key = toasted_key || '1';
  
  DELETE FROM toasted_key;
  
  -- Test that HEAP2_MULTI_INSERT insertions with and without toasted
  -- columns are handled correctly
  CREATE TABLE toasted_copy (
      id int primary key, -- no default, copy didn't use to handle that with multi inserts
      data text
  );
  ALTER TABLE toasted_copy ALTER COLUMN data SET STORAGE EXTERNAL;
  \copy toasted_copy FROM STDIN
  1	untoasted1
  2	toasted1-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
  3	untoasted2
  4	toasted2-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
  5	untoasted3
  6	untoasted4
  7	untoasted5
  8	untoasted6
  9	untoasted7
  10	untoasted8
  11	untoasted9
  12	untoasted10
  13	untoasted11
  14	untoasted12
  15	untoasted13
  16	untoasted14
  17	untoasted15
  18	untoasted16
  19	untoasted17
  20	untoasted18
  21	untoasted19
  22	untoasted20
  23	untoasted21
  24	untoasted22
  25	untoasted23
  26	untoasted24
  27	untoasted25
  28	untoasted26
  29	untoasted27
  30	untoasted28
  31	untoasted29
  32	untoasted30
  33	untoasted31
  34	untoasted32
  35	untoasted33
  36	untoasted34
  37	untoasted35
  38	untoasted36
  39	untoasted37
  40	untoasted38
  41	untoasted39
  42	untoasted40
  43	untoasted41
  44	untoasted42
  45	untoasted43
  46	untoasted44
  47	untoasted45
  48	untoasted46
  49	untoasted47
  50	untoasted48
  51	untoasted49
  52	untoasted50
  53	untoasted51
  54	untoasted52
  55	untoasted53
  56	untoasted54
  57	untoasted55
  58	untoasted56
  59	untoasted57
  60	untoasted58
  61	untoasted59
  62	untoasted60
  63	untoasted61
  64	untoasted62
  65	untoasted63
  66	untoasted64
  67	untoasted65
  68	untoasted66
  69	untoasted67
  70	untoasted68
  71	untoasted69
  72	untoasted70
  73	untoasted71
  74	untoasted72
  75	untoasted73
  76	untoasted74
  77	untoasted75
  78	untoasted76
  79	untoasted77
  80	untoasted78
  81	untoasted79
  82	untoasted80
  83	untoasted81
  84	untoasted82
  85	untoasted83
  86	untoasted84
  87	untoasted85
  88	untoasted86
  89	untoasted87
  90	untoasted88
  91	untoasted89
  92	untoasted90
  93	untoasted91
  94	untoasted92
  95	untoasted93
  96	untoasted94
  97	untoasted95
  98	untoasted96
  99	untoasted97
  100	untoasted98
  101	untoasted99
  102	untoasted100
  103	untoasted101
  104	untoasted102
  105	untoasted103
  106	untoasted104
  107	untoasted105
  108	untoasted106
  109	untoasted107
  110	untoasted108
  111	untoasted109
  112	untoasted110
  113	untoasted111
  114	untoasted112
  115	untoasted113
  116	untoasted114
  117	untoasted115
  118	untoasted116
  119	untoasted117
  120	untoasted118
  121	untoasted119
  122	untoasted120
  123	untoasted121
  124	untoasted122
  125	untoasted123
  126	untoasted124
  127	untoasted125
  128	untoasted126
  129	untoasted127
  130	untoasted128
  131	untoasted129
  132	untoasted130
  133	untoasted131
  134	untoasted132
  135	untoasted133
  136	untoasted134
  137	untoasted135
  138	untoasted136
  139	untoasted137
  140	untoasted138
  141	untoasted139
  142	untoasted140
  143	untoasted141
  144	untoasted142
  145	untoasted143
  146	untoasted144
  147	untoasted145
  148	untoasted146
  149	untoasted147
  150	untoasted148
  151	untoasted149
  152	untoasted150
  153	untoasted151
  154	untoasted152
  155	untoasted153
  156	untoasted154
  157	untoasted155
  158	untoasted156
  159	untoasted157
  160	untoasted158
  161	untoasted159
  162	untoasted160
  163	untoasted161
  164	untoasted162
  165	untoasted163
  166	untoasted164
  167	untoasted165
  168	untoasted166
  169	untoasted167
  170	untoasted168
  171	untoasted169
  172	untoasted170
  173	untoasted171
  174	untoasted172
  175	untoasted173
  176	untoasted174
  177	untoasted175
  178	untoasted176
  179	untoasted177
  180	untoasted178
  181	untoasted179
  182	untoasted180
  183	untoasted181
  184	untoasted182
  185	untoasted183
  186	untoasted184
  187	untoasted185
  188	untoasted186
  189	untoasted187
  190	untoasted188
  191	untoasted189
  192	untoasted190
  193	untoasted191
  194	untoasted192
  195	untoasted193
  196	untoasted194
  197	untoasted195
  198	untoasted196
  199	untoasted197
  200	untoasted198
  201	toasted3-12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890
  202	untoasted199
  203	untoasted200
  \.
  SELECT substr(data, 1, 200) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
  
  -- test we can decode "old" tuples bigger than the max heap tuple size correctly
  DROP TABLE IF EXISTS toasted_several;
  CREATE TABLE toasted_several (
      id serial unique not null,
      toasted_key text primary key,
      toasted_col1 text,
      toasted_col2 text
  );
  ALTER TABLE toasted_several REPLICA IDENTITY FULL;
  ALTER TABLE toasted_several ALTER COLUMN toasted_key SET STORAGE EXTERNAL;
  ALTER TABLE toasted_several ALTER COLUMN toasted_col1 SET STORAGE EXTERNAL;
  ALTER TABLE toasted_several ALTER COLUMN toasted_col2 SET STORAGE EXTERNAL;
  
  -- Change the storage of the index back to EXTENDED, separately from
  -- the table.  This is currently not doable via DDL, but it is
  -- supported internally.
  UPDATE pg_attribute SET attstorage = 'x' WHERE attrelid = 'toasted_several_pkey'::regclass AND attname = 'toasted_key';
  
  INSERT INTO toasted_several(toasted_key) VALUES(repeat('9876543210', 10000));
  SELECT pg_column_size(toasted_key) > 2^16 FROM toasted_several;
  
  SELECT regexp_replace(data, '^(.{100}).*(.{100})$', '\1..\2') FROM pg_logical_slot_peek_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
  
  -- test update of a toasted key without changing it
  UPDATE toasted_several SET toasted_col1 = toasted_key;
  UPDATE toasted_several SET toasted_col2 = toasted_col1;
  
  SELECT regexp_replace(data, '^(.{100}).*(.{100})$', '\1..\2') FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');
  
  /*
   * update with large tuplebuf, in a transaction large enough to force to spool to disk
   */
  BEGIN;
  INSERT INTO toasted_several(toasted_key) SELECT * FROM generate_series(1, 10234);
  UPDATE toasted_several SET toasted_col1 = toasted_col2 WHERE id = 1;
  DELETE FROM toasted_several WHERE id = 1;
  COMMIT;
  
  DROP TABLE toasted_several;
  
  SELECT regexp_replace(data, '^(.{100}).*(.{100})$', '\1..\2') FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1')
  WHERE data NOT LIKE '%INSERT: %';
  SELECT pg_drop_replication_slot('regression_slot');
  