├── .github └── workflows │ └── test.yml ├── .gitignore ├── Makefile ├── README.md ├── conv ├── euc_jp_to_utf8.extra ├── euc_jp_to_utf8.map └── euc_jp_to_utf8.radix ├── expected ├── pg_94_or_later.out ├── pg_advance_vacuum_cleanup_age.out ├── pg_cached_plan.out ├── pg_cheat_funcs.out ├── pg_chr.out ├── pg_chr_91_93.out ├── pg_eucjp.out ├── pg_saslprep.out ├── pg_stat_get_memory_context.out ├── pg_stat_print_memory_context.out ├── pg_xid_to_xid8.out └── pglz_compress.out ├── pg_cheat_funcs--1.0.sql ├── pg_cheat_funcs.c ├── pg_cheat_funcs.control └── sql ├── pg_94_or_later.sql ├── pg_advance_vacuum_cleanup_age.sql ├── pg_cached_plan.sql ├── pg_cheat_funcs.sql ├── pg_chr.sql ├── pg_chr_91_93.sql ├── pg_eucjp.sql ├── pg_saslprep.sql ├── pg_stat_get_memory_context.sql ├── pg_stat_print_memory_context.sql ├── pg_xid_to_xid8.sql └── pglz_compress.sql /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: test 2 | 3 | on: 4 | push: 5 | branches: 6 | - "*" 7 | 8 | jobs: 9 | test: 10 | name: regression test 11 | runs-on: ubuntu-latest 12 | strategy: 13 | fail-fast: true 14 | matrix: 15 | pgbranch: 16 | - master 17 | - REL_16_STABLE 18 | - REL_15_STABLE 19 | - REL_14_STABLE 20 | - REL_13_STABLE 21 | - REL_12_STABLE 22 | - REL_11_STABLE 23 | - REL_10_STABLE 24 | env: 25 | PGBRANCH: ${{ matrix.pgbranch }} 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: set_env 29 | run: | 30 | echo "PGHOME=${HOME}/${PGBRANCH}" >> $GITHUB_ENV 31 | echo "PGDATA=${HOME}/pgdata" >> $GITHUB_ENV 32 | - name: add_path 33 | run: | 34 | echo "${PGHOME}/bin" >> $GITHUB_PATH 35 | - name: before_install 36 | run: | 37 | git clone -b ${PGBRANCH} --depth 1 https://github.com/postgres/postgres.git 38 | cd postgres 39 | ./configure --prefix=${PGHOME} --enable-debug --enable-cassert 40 | make -j 2 -s 41 | make -s install 42 | initdb -D ${PGDATA} --locale=C --encoding=UTF8 43 | pg_ctl -D ${PGDATA} -w start 44 | - name: before_script 45 | run: | 46 | cd ${GITHUB_WORKSPACE} 47 | make USE_PGXS=1 PG_CONFIG=${PGHOME}/bin/pg_config 48 | make USE_PGXS=1 PG_CONFIG=${PGHOME}/bin/pg_config install 49 | - name: script 50 | run: | 51 | make USE_PGXS=1 PG_CONFIG=${PGHOME}/bin/pg_config installcheck 52 | - name: after_script_failure 53 | if: failure() 54 | run: | 55 | if [ -f regression.diffs ]; then cat regression.diffs; fi 56 | exit 1 57 | - name: after_script_success 58 | if: success() 59 | run: | 60 | echo "SUCCESS" 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Global excludes across all subdirectories 2 | *.o 3 | *.so 4 | regression.* 5 | 6 | # Generated subdirectories 7 | /results/ 8 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | MODULE_big = pg_cheat_funcs 2 | OBJS = pg_cheat_funcs.o 3 | 4 | EXTENSION = pg_cheat_funcs 5 | DATA = pg_cheat_funcs--1.0.sql 6 | 7 | REGRESS = pg_cheat_funcs pg_eucjp 8 | 9 | MAJORVERSION_INT = $(shell echo $(MAJORVERSION).0 | cut -d . -f 1-2 | tr -d .) 10 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -ge 100 ]; then echo pg_saslprep; fi) 11 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -ge 96 -a $(MAJORVERSION_INT) -lt 140 ]; then echo pg_stat_get_memory_context; fi) 12 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -lt 140 ]; then echo pg_stat_print_memory_context; fi) 13 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -ge 95 ]; then echo pglz_compress; fi) 14 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -ge 94 ]; then echo pg_chr pg_94_or_later; else echo pg_chr_91_93; fi) 15 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -ge 92 ]; then echo pg_cached_plan; fi) 16 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -ge 130 ]; then echo pg_xid_to_xid8; fi) 17 | REGRESS += $(shell if [ $(MAJORVERSION_INT) -lt 160 ]; then echo pg_advance_vacuum_cleanup_age; fi) 18 | 19 | PGFILEDESC = "pg_cheat_funcs - provides cheat (but useful) functions" 20 | 21 | ifdef USE_PGXS 22 | PG_CONFIG = pg_config 23 | PGXS := $(shell $(PG_CONFIG) --pgxs) 24 | include $(PGXS) 25 | else 26 | subdir = contrib/pg_cheat_funcs 27 | top_builddir = ../.. 28 | include $(top_builddir)/src/Makefile.global 29 | include $(top_srcdir)/contrib/contrib-global.mk 30 | endif 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # pg_cheat_funcs 2 | This extension provides cheat (but useful) functions on PostgreSQL. 3 | 4 | pg_cheat_funcs is released under the [PostgreSQL License](https://opensource.org/licenses/postgresql), a liberal Open Source license, similar to the BSD or MIT licenses. 5 | 6 | ## Test Status 7 | [![Build Status](https://github.com/MasaoFujii/pg_cheat_funcs/actions/workflows/test.yml/badge.svg)](https://github.com/MasaoFujii/pg_cheat_funcs/actions/workflows/test.yml) 8 | 9 | ## Install 10 | 11 | Download the source archive of pg_cheat_funcs from 12 | [here](https://github.com/MasaoFujii/pg_cheat_funcs), 13 | and then build and install it. 14 | 15 | $ cd pg_cheat_funcs 16 | $ make USE_PGXS=1 PG_CONFIG=/opt/pgsql-X.Y.Z/bin/pg_config 17 | $ su 18 | # make USE_PGXS=1 PG_CONFIG=/opt/pgsql-X.Y.Z/bin/pg_config install 19 | # exit 20 | 21 | USE_PGXS=1 must be always specified when building this extension. 22 | The path to [pg_config](http://www.postgresql.org/docs/devel/static/app-pgconfig.html) 23 | (which exists in the bin directory of PostgreSQL installation) 24 | needs be specified in PG_CONFIG. 25 | However, if the PATH environment variable contains the path to pg_config, 26 | PG_CONFIG doesn't need to be specified. 27 | 28 | ## Functions 29 | 30 | Note that **CREATE EXTENSION pg_cheat_funcs** needs to be executed 31 | in all the databases that you want to execute the functions that 32 | this extension provides. 33 | 34 | =# CREATE EXTENSION pg_cheat_funcs; 35 | 36 | ### SETOF record pg_stat_get_memory_context() 37 | Return statistics about all memory contexts. 38 | This function returns a record, shown in the table below. 39 | 40 | | Column Name | Data Type | Description | 41 | |---------------|-----------|------------------------------------------------| 42 | | name | text | context name | 43 | | parent | text | name of parent context | 44 | | level | integer | distance from TopMemoryContext in context tree | 45 | | total_bytes | bigint | total bytes requested from malloc | 46 | | total_nblocks | bigint | total number of malloc blocks | 47 | | free_bytes | bigint | free space in bytes | 48 | | free_chunks | bigint | number of free chunks | 49 | | used_bytes | bigint | used space in bytes | 50 | 51 | This function is available only in between PostgreSQL 9.6 and 13. 52 | Since 14, PostgreSQL core provides the view 53 | [pg_backend_memory_contexts](https://www.postgresql.org/docs/devel/view-pg-backend-memory-contexts.html) 54 | that displays all the memory contexts of the server process 55 | attached to the current session. 56 | 57 | This function is restricted to superusers by default, 58 | but other users can be granted EXECUTE to run the function. 59 | 60 | ### void pg_stat_print_memory_context() 61 | Cause statistics about all memory contexts to be logged. 62 | The format of log message for each memory context is: 63 | 64 | [name]: [total_bytes] total in [total_nblocks] blocks; [free_bytes] free ([free_chunks] chunks); [used_bytes] used 65 | 66 | For descriptions of the above fields, please see [pg_stat_get_memory_context()](#setof-record-pg_stat_get_memory_context). 67 | 68 | This function is available only in PostgreSQL 13 or before. 69 | Since 14, PostgreSQL core provides the function 70 | [pg_log_backend_memory_contexts](https://www.postgresql.org/docs/devel/functions-admin.html#FUNCTIONS-ADMIN-SIGNAL) 71 | that requests to log the memory contexts of the backend with 72 | the specified process ID. 73 | 74 | This function is restricted to superusers by default, 75 | but other users can be granted EXECUTE to run the function. 76 | 77 | ### record pg_cached_plan_source(stmt text) 78 | Return information about cached plan source of the specified prepared statement. 79 | This function returns a record, shown in the table below. 80 | 81 | | Column Name | Data Type | Description | 82 | |-------------------|------------------|------------------------------------------| 83 | | generic_cost | double precision | cost of generic plan, or -1 if not known | 84 | | total_custom_cost | double precision | total cost of custom plans so far | 85 | | num_custom_plans | integer | number of plans included in total | 86 | | force_generic | boolean | force use of generic plan? | 87 | | force_custom | boolean | force use of custom plan? | 88 | 89 | This function is available only in PostgreSQL 9.2 or later. 90 | 91 | ### void pg_signal_process(pid int, signame text) 92 | Send a signal to PostgreSQL server process. 93 | This function can signal to only postmaster, backend, walsender and walreceiver process. 94 | Valid signal names are HUP, INT, QUIT, ABRT, KILL, TERM, USR1, USR2, CONT, and STOP. 95 | This function is restricted to superusers by default, 96 | but other users can be granted EXECUTE to run the function. 97 | 98 | For example, terminate walreceiver process: 99 | 100 | -- Note that pg_stat_wal_receiver view is available in 9.6 or later 101 | =# SELECT pg_signal_process(pid, 'TERM') FROM pg_stat_wal_receiver; 102 | 103 | ### integer pg_get_priority(pid int) 104 | Return the scheduling priority ("nice") of the specified PostgreSQL server process. 105 | This function can get the priority of only postmaster, backend, walsender and 106 | walreceiver process. 107 | See getpriority(2) man page for details about a scheduling priority. 108 | This function is restricted to superusers by default, 109 | but other users can be granted EXECUTE to run the function. 110 | 111 | ### void pg_set_priority(pid int, priority int) 112 | Set the scheduling priority ("nice") of the specified PostgreSQL server process to the specified value. 113 | This function can change the priority of only postmaster, backend, walsender and 114 | walreceiver process. 115 | See getpriority(2) man page for details about a scheduling priority. 116 | This function is restricted to superusers by default, 117 | but other users can be granted EXECUTE to run the function. 118 | 119 | ### void pg_segmentation_fault(treat_fatal_as_error boolean) 120 | Cause segmentation fault. 121 | If pg_cheat_funcs.exit_on_segv is enabled and treat_fatal_as_error is true, 122 | segmentation fault that this function causes will lead to ERROR instead of 123 | FATAL error. This is intended mainly for testing. 124 | This function is restricted to superusers by default, 125 | but other users can be granted EXECUTE to run the function. 126 | 127 | ### void pg_process_config_file() 128 | Read and process the configuration file. 129 | Note that, if an error occurs, it's logged with DEBUG2 level. 130 | This function is restricted to superusers by default, 131 | but other users can be granted EXECUTE to run the function. 132 | 133 | ### text pg_xlogfile_name(location pg_lsn, recovery boolean) 134 | Convert transaction log location string to file name. 135 | This function is almost the same as pg_walfile_name() 136 | (or pg_xlogfile_name in 9.6 or before) which PostgreSQL core provides. 137 | The difference of them is whether there is a second parameter of type boolean. 138 | If false, this function always fails with an error during recovery. 139 | This is the same behavior as the core version of pg_walfile_name(). 140 | If true, this function can be executed even during recovery. 141 | But note that the first 8 digits of returned WAL filename 142 | (which represents the timeline ID) can be completely incorrect. 143 | That is, this function can return bogus WAL file name. 144 | For details of this conversion, please see [PostgreSQL document](http://www.postgresql.org/docs/devel/static/functions-admin.html#FUNCTIONS-ADMIN-BACKUP). 145 | This function is available only in PostgreSQL 9.4 or later. 146 | 147 | ### pg_lsn max(SETOF pg_lsn) 148 | This is max() aggregate function for pg_lsn data type. 149 | This aggregate function computes and returns a maximum pg_lsn value 150 | from a set of pg_lsn input values. 151 | This function is available only in between PostgreSQL 9.4 and 12. 152 | Since 13, this is supported in PostgreSQL core. 153 | 154 | ### pg_lsn min(SETOF pg_lsn) 155 | This is min() aggregate function for pg_lsn data type. 156 | This aggregate function computes and returns a minimum pg_lsn value 157 | from a set of pg_lsn input values. 158 | This function is available only in between PostgreSQL 9.4 and 12. 159 | Since 13, this is supported in PostgreSQL core. 160 | 161 | ### SETOF record pg_stat_get_syncrep_waiters() 162 | Return statistics about all server processes waiting for 163 | synchronous replication. 164 | This function returns a record per server process waiting for 165 | synchronous replication, shown in the table below. 166 | 167 | | Column Name | Data Type | Description | 168 | |-------------|-----------|--------------------------------------| 169 | | pid | integer | Process ID of a server process | 170 | | wait_lsn | pg_lsn | Transaction log position to wait for | 171 | | wait_mode | text | Wait mode of this server process | 172 | 173 | Possible values of wait_mode are write, flush and apply 174 | (only in PostgreSQL 9.6 or later). 175 | 176 | This function is available only in PostgreSQL 9.4 or later. 177 | This function is restricted to superusers by default, 178 | but other users can be granted EXECUTE to run the function. 179 | 180 | ### void pg_wait_syncrep(location pg_lsn) 181 | Wait for synchronous replication. 182 | This function waits until the given transaction log location is acknowledged 183 | by synchronous standbys, based on the setting of 184 | [synchronous_commit](http://www.postgresql.org/docs/devel/static/runtime-config-wal.html#GUC-SYNCHRONOUS-COMMIT). 185 | 186 | This function is available only in PostgreSQL 9.4 or later. 187 | This function is restricted to superusers by default, 188 | but other users can be granted EXECUTE to run the function. 189 | 190 | ### void pg_refresh_snapshot() 191 | Forcibly refresh the current snapshot whatever transaction isolation 192 | level is used. 193 | 194 | Note that this is extremely dangerous function and can easily break 195 | transaction isolation. 196 | This function must not be used for a purpose other than debug. 197 | 198 | This function is available only in PostgreSQL 9.4 or later. 199 | This function is restricted to superusers by default, 200 | but other users can be granted EXECUTE to run the function. 201 | 202 | ### xid pg_set_next_xid(transactionid xid) 203 | Set and return the next transaction ID. 204 | Note that this function doesn't check if it's safe to assign 205 | the given transaction ID to the next one. 206 | The caller must carefully choose the safe transaction ID, 207 | e.g., which doesn't cause a transaction ID wraparound problem. 208 | This function is restricted to superusers by default, 209 | but other users can be granted EXECUTE to run the function. 210 | 211 | ### SETOF record pg_xid_assignment() 212 | Return information about transaction ID assignment state. 213 | This function returns a record, shown in the table below. 214 | 215 | | Column Name | Data Type | Description | 216 | |----------------|-----------|---------------------------------------------------| 217 | | next_xid | xid | next transaction ID to assign | 218 | | oldest_xid | xid | cluster-wide minimum datfrozenxid | 219 | | xid_vac_limit | xid | start forcing autovacuums here | 220 | | xid_warn_limit | xid | start complaining here | 221 | | xid_stop_limit | xid | refuse to advance next transaction ID beyond here | 222 | | xid_wrap_limit | xid | where the world ends | 223 | | oldest_xid_db | oid | database with minimum datfrozenxid | 224 | 225 | This function is restricted to superusers by default, 226 | but other users can be granted EXECUTE to run the function. 227 | 228 | ### xid8 pg_xid_to_xid8 (transactionid xid) 229 | Convert the specified transaction ID with 32-bit type xid to 230 | the transaction ID with 64-bit type xid8. 231 | The specified transaction ID must be from the same epoch as 232 | the latest transaction ID, or the epoch before. 233 | For example, the currently used xid like pg_stat_activity.backend_xid 234 | or pg_locks.transactionid can be specified in this function. 235 | 236 | This function is available only in PostgreSQL 13 or later. 237 | 238 | ### xid pg_set_next_oid(objectid oid) 239 | Set and return the next object ID (OID). 240 | Note that the next OID is set to 16384 (FirstNormalObjectId) 241 | when the given OID is less than that number. 242 | This function is restricted to superusers by default, 243 | but other users can be granted EXECUTE to run the function. 244 | 245 | ### SETOF record pg_oid_assignment() 246 | Return information about object ID (OID) assignment state. 247 | This function returns a record, shown in the table below. 248 | 249 | | Column Name | Data Type | Description | 250 | |-------------|-----------|----------------------------------------| 251 | | next_oid | oid | next object ID to assign | 252 | | oid_count | integer | OIDs available before must do WAL work | 253 | 254 | This function is restricted to superusers by default, 255 | but other users can be granted EXECUTE to run the function. 256 | 257 | ### integer pg_advance_vacuum_cleanup_age(integer) 258 | Specify the number of transactions by which VACUUM and HOT updates 259 | will advance cleanup of dead row versions. 260 | [vacuum_defer_cleanup_age](https://www.postgresql.org/docs/devel/static/runtime-config-replication.html#GUC-VACUUM-DEFER-CLEANUP-AGE) 261 | in the session calling this function is set to 262 | the negative value of that specified number. If the argument is omitted 263 | or NULL is specified, vacuum_defer_cleanup_age is reset to 264 | its original setting value specified in the configuration file. 265 | This function returns the vacuum cleanup age. 266 | 267 | By advancing the cleanup age, VACUUM and HOT updates can clean up 268 | even dead tuples that were produced since oldest transaction had started. 269 | So this function is helpful to prevent the database from bloating due to 270 | unremovable dead tuples while long transaction is running. 271 | 272 | Note that this is extremely dangerous function and can easily corrupt 273 | the database. Any important data may disappear and data consistency 274 | may be lost completely. 275 | This function must not be used for a purpose other than debug. 276 | 277 | This function is restricted to superusers by default, 278 | but other users can be granted EXECUTE to run the function. 279 | 280 | This function is available only in PostgreSQL 15 or earlier, 281 | as the vacuum_defer_cleanup_age that it depends on was removed in 16. 282 | 283 | ### void pg_checkpoint(fast bool, wait bool, force bool) 284 | Perform a checkpoint. 285 | If fast is true (default), a checkpoint will finish as soon as possible. 286 | Otherwise, I/O required for a checkpoint will be spread out over 287 | a period of time, to minimize the impact on query processing. 288 | If wait is true (default), this function waits for a checkpoint to complete 289 | before returning. Otherwise, it just signals checkpointer to do it and returns. 290 | If force is true (default), this function forces a checkpoint even if no WAL 291 | activity has occurred since the last one. 292 | This function is restricted to superusers by default, 293 | but other users can be granted EXECUTE to run the function. 294 | 295 | ### void pg_promote(fast bool) 296 | Promote the standby server. 297 | If fast is true (default), this function requests for fast promotion. 298 | In fast mode, standby promotion only creates a lightweight 299 | end-of-recovery record instead of a full checkpoint. 300 | A checkpoint is requested later, after we're fully out of recovery mode 301 | and already accepting queries. 302 | If fast is false, this function requests for fallback version of promotion. 303 | In this mode, a full checkpoint is created at the end of recovery. 304 | Note that fallback version of promotion is performed 305 | in PostgreSQL 9.2 or before whether fast is true or false 306 | because fast promotion is available only in 9.3 or later. 307 | This function is restricted to superusers by default, 308 | but other users can be granted EXECUTE to run the function. 309 | 310 | This function is available only in 11 or before. 311 | Since 12, this is supported in PostgreSQL core. 312 | 313 | ### SETOF record pg_recovery_settings() 314 | Return information about all parameter settings in recovery.conf. 315 | This function returns a record, shown in the table below. 316 | 317 | | Column Name | Data Type | Description | 318 | |-------------|-----------|------------------------------| 319 | | name | text | configuration parameter name | 320 | | setting | text | value of the parameter | 321 | 322 | This function is restricted to superusers by default, 323 | but other users can be granted EXECUTE to run the function. 324 | 325 | ### text pg_show_primary_conninfo() 326 | Return the current value of primary_conninfo recovery parameter. 327 | If it's not set yet, NULL is returned. 328 | This function is restricted to superusers by default, 329 | but other users can be granted EXECUTE to run the function. 330 | For details of primary_conninfo parameter, please see [PostgreSQL document](http://www.postgresql.org/docs/devel/static/standby-settings.html). 331 | 332 | ### integer pg_postmaster_pid() 333 | Return the Process ID of the postmaster process. 334 | 335 | ### timestamp with time zone pg_backend_start_time() 336 | Return the time when the server process attached to the current session 337 | was started. 338 | 339 | ### SETOF text pg_list_relation_filepath(relation regclass) 340 | List the file path names of the specified relation. 341 | Note that this function returns only the path name of 342 | the first segment file in PostgreSQL 9.4 or before. 343 | 344 | ### text pg_tablespace_version_direcotry() 345 | Return the name of major-version-specific tablespace subdirectory. 346 | 347 | ### bigint pg_file_write_binary(filepath text, data bytea) 348 | Write bytea data to the file. 349 | This function creates the file if it does not exist, 350 | and truncates it to zero length otherwise. 351 | Then this function writes the bytea data from the beginning of the file, 352 | and returns the number of bytes written. 353 | This function is restricted to superusers by default, 354 | but other users can be granted EXECUTE to run the function. 355 | 356 | ### void pg_file_fsync(filepath text) 357 | Try to fsync the file or directory. 358 | This function is available only in PostgreSQL 9.4 or later. 359 | This function is restricted to superusers by default, 360 | but other users can be granted EXECUTE to run the function. 361 | 362 | ### text to_octal(integer or bigint) 363 | Convert number to its equivalent octal representation. 364 | 365 | ### text pg_text_to_hex(str text) 366 | Convert text to its equivalent hexadecimal representation. 367 | 368 | Here is an example of the conversion from text to hex: 369 | 370 | =# SELECT pg_text_to_hex('PostgreSQL'); 371 | pg_text_to_hex 372 | ---------------------- 373 | 506f737467726553514c 374 | (1 row) 375 | 376 | ### text pg_hex_to_text(hex text) 377 | Convert hexadecimal representation to its equivalent text. 378 | 379 | Here is an example of the conversion from hex to text: 380 | 381 | =# SELECT pg_hex_to_text('506f737467726553514c'); 382 | pg_hex_to_text 383 | ---------------- 384 | PostgreSQL 385 | (1 row) 386 | 387 | ### text pg_chr(code integer) 388 | Return the character with the given code. 389 | This function is almost the same as chr() which PostgreSQL core provides. 390 | The difference of them is that this function returns NULL instead of 391 | throwing an error when the requested character is too large or not valid. 392 | Note that valid Unicode code point stops at U+10FFFF (1114111), 393 | even though 4-byte UTF8 sequences can hold values up to U+1FFFFF. 394 | Therefore this function returns NULL whenever the given code is larger 395 | than 1114111. 396 | 397 | ### text pg_utf8(code integer) 398 | Alias of [pg_chr](https://github.com/MasaoFujii/pg_cheat_funcs#text-pg_chrcode-integer) function. 399 | 400 | ### SETOF record pg_all_utf8() 401 | Return all valid UTF-8 characters. 402 | This function returns a record, shown in the table below. 403 | 404 | | Column Name | Data Type | Description | 405 | |-------------|-----------|-------------------| 406 | | code | text | code of character | 407 | | utf8 | text | UTF-8 character | 408 | 409 | This function can be executed only under UTF-8 database encoding. 410 | 411 | ### text pg_eucjp(code1 bit(8), code2 bit(8), code3 bit(8)) 412 | Return EUC_JP character with the given codes. 413 | The following table shows the valid combination of the codes. 414 | 415 | | code1 | code2 | code3 | 416 | |-----------|-----------|-----------| 417 | | x00 - x7f | - | - | 418 | | x8e | xa1 - xdf | - | 419 | | xa1 - xfe | xa1 - xfe | - | 420 | | x8f | xa1 - xfe | xa1 - xfe | 421 | 422 | For example, return EUC_JP character with 'a1fa' (BLACK STAR): 423 | 424 | =# SELECT pg_eucjp('xa1', 'xfa'); 425 | 426 | This function returns NULL when the requested character is invalid for EUC_JP. 427 | This function can be executed only under EUC_JP database encoding. 428 | 429 | ### SETOF record pg_all_eucjp() 430 | Return all valid EUC_JP characters. 431 | This function returns a record, shown in the table below. 432 | 433 | | Column Name | Data Type | Description | 434 | |-------------|-----------|-----------------------------------------------------------------| 435 | | code1 | text | first byte of character | 436 | | code2 | text | second byte of character (x00 means non-existence of this byte) | 437 | | code3 | text | third byte of character (x00 means non-existence of this byte) | 438 | | eucjp | text | EUC_JP character | 439 | 440 | This function can be executed only under EUC_JP database encoding. 441 | 442 | ### bytea pglz_compress(data text) 443 | Create and return a compressed version of text data. 444 | This function uses PGLZ (an implementation of LZ compression for PostgreSQL) 445 | for the compression. 446 | If the compression fails (e.g., the compressed result is actually 447 | bigger than the original), this function returns the original data. 448 | Note that the return data may be 4-bytes bigger than the original 449 | even when the compression fails because 4-bytes extra information 450 | like the length of original data is always stored in it. 451 | The bytea data that this function returns needs to be decompressed 452 | by using pg_lz_decompress() to obtain the original text data. 453 | This function is available only in PostgreSQL 9.5 or later. 454 | 455 | ### bytea pglz_compress_bytea(data bytea) 456 | Create and return a compressed version of bytea data. 457 | This function uses PGLZ (an implementation of LZ compression for PostgreSQL) 458 | for the compression. 459 | If the compression fails (e.g., the compressed result is actually 460 | bigger than the original), this function returns the original data. 461 | Note that the return data may be 4-bytes bigger than the original 462 | even when the compression fails because 4-bytes extra information 463 | like the length of original data is always stored in it. 464 | The bytea data that this function returns needs to be decompressed 465 | by using pg_lz_decompress_bytea() to obtain the original bytea data. 466 | This function is available only in PostgreSQL 9.5 or later. 467 | 468 | ### text pglz_decompress(data bytea) 469 | Decompress a compressed version of bytea data into text. 470 | Note that the input of this function must be the bytea data that 471 | pg_lz_compress() or pg_lz_compress_bytea() returned. 472 | Otherwise this function may return a corrupted data. 473 | This function is available only in PostgreSQL 9.5 or later. 474 | 475 | ### bytea pglz_decompress_bytea(data bytea) 476 | Decompress a compressed version of bytea data into bytea. 477 | Note that the input of this function must be the bytea data that 478 | pg_lz_compress() or pg_lz_compress_bytea() returned. 479 | Otherwise this function may return a corrupted data. 480 | This function is available only in PostgreSQL 9.5 or later. 481 | 482 | ### text pg_saslprep(input text) 483 | Normalize an input string with SASLprep. 484 | SASLprep normalization is basically used to process a user-supplied 485 | password into canonical form for SCRAM authentication. 486 | Note that an error is raised if the input is not a valid UTF-8 string or 487 | the normalized string contains characters prohibited by the SASLprep profile. 488 | This function is available only in PostgreSQL 10 or later. 489 | 490 | ### pg_advisory_xact_unlock (bigint) 491 | Release a previously-acquired exclusive transaction-level advisory lock. 492 | Return true if the lock is successfully released. If the lock was not held, 493 | false is returned, and in addition, an SQL warning will be reported 494 | by the server. 495 | 496 | ### pg_advisory_xact_unlock_shared (bigint) 497 | Release a previously-acquired shared transaction-level advisory lock. 498 | Return true if the lock is successfully released. If the lock was not held, 499 | false is returned, and in addition, an SQL warning will be reported 500 | by the server. 501 | 502 | ### pg_advisory_xact_unlock (integer, integer) 503 | Same as pg_advisory_xact_unlock(bigint). 504 | 505 | ### pg_advisory_xact_unlock_shared (integer, integer) 506 | Same as pg_advisory_xact_unlock_shared(bigint). 507 | 508 | ## Encoding Conversions 509 | 510 | ### pg_euc_jp_to_utf8 511 | This is an encoding conversion from EUC_JP to UTF-8. 512 | It uses two conversion maps; ordinary map and extra map. 513 | They are defined in `conv/euc_jp_to_utf8.map` and `conv/euc_jp_to_utf8.extra`, 514 | respectively. 515 | For each character, ordinary map is consulted first. 516 | If no match is found, extra map is consulted next. 517 | If still no match, an error is raised. 518 | 519 | The content of ordinary map is the same as the map that euc_jp_to_utf8 520 | (default conversion map from EUC_JP to UTF-8 that PostgreSQL provides) uses. 521 | The extra map contains some mappings (e.g., the following mappings for 522 | Roman numerals and full-width symbols) that ordinary map doesn't have. 523 | 524 | | EUC_JP | UTF-8 | Description | 525 | |--------|-----------------|---------------------------| 526 | | fcf1 | e285b0 (U+2170) | SMALL ROMAN NUMERAL ONE | 527 | | fcf2 | e285b1 (U+2171) | SMALL ROMAN NUMERAL TWO | 528 | | fcf3 | e285b2 (U+2172) | SMALL ROMAN NUMERAL THREE | 529 | | fcf4 | e285b3 (U+2173) | SMALL ROMAN NUMERAL FOUR | 530 | | fcf5 | e285b4 (U+2174) | SMALL ROMAN NUMERAL FIVE | 531 | | fcf6 | e285b5 (U+2175) | SMALL ROMAN NUMERAL SIX | 532 | | fcf7 | e285b6 (U+2176) | SMALL ROMAN NUMERAL SEVEN | 533 | | fcf8 | e285b7 (U+2177) | SMALL ROMAN NUMERAL EIGHT | 534 | | fcf9 | e285b8 (U+2178) | SMALL ROMAN NUMERAL NINE | 535 | | fcfa | e285b9 (U+2179) | SMALL ROMAN NUMERAL TEN | 536 | | fcfb | efbfa2 (U+FFE2) | FULLWIDTH NOT SIGN | 537 | | fcfc | efbfa4 (U+FFE4) | FULLWIDTH BROKEN BAR | 538 | | fcfd | efbc87 (U+FF07) | FULLWIDTH APOSTROPHE | 539 | | fcfe | efbc82 (U+FF02) | FULLWIDTH QUOTATION MARK | 540 | 541 | In order to use pg_euc_jp_to_utf8 as the default conversion from EUC_JP to 542 | UTF-8, its [pg_conversion](http://www.postgresql.org/docs/devel/static/catalog-pg-conversion.html).condefault 543 | needs to be enabled. Also condefault for euc_jp_to_utf8 (built-in conversion 544 | from EUC_JP to UTF-8) needs to be disabled. 545 | Here is an example of these catalog updates: 546 | 547 | =# BEGIN; 548 | =# UPDATE pg_conversion SET condefault = 'f' WHERE conname = 'euc_jp_to_utf8'; 549 | =# UPDATE pg_conversion SET condefault = 't' WHERE conname = 'pg_euc_jp_to_utf8'; 550 | =# COMMIT; 551 | 552 | It's possible to use the customized conversion map by modifying the map files 553 | directly and rebuilding pg_cheat_funcs module. 554 | Note that entries in a map file must be sorted in ascending order. 555 | 556 | ## Configuration Parameters 557 | 558 | Note that [shared_preload_libraries](http://www.postgresql.org/docs/devel/static/runtime-config-client.html#GUC-SHARED-PRELOAD-LIBRARIES) 559 | or [session_preload_libraries](http://www.postgresql.org/docs/devel/static/runtime-config-client.html#GUC-SESSION-PRELOAD-LIBRARIES) 560 | (available in PostgreSQL 9.4 or later) must be set to 'pg_cheat_funcs' 561 | in postgresql.conf 562 | if you want to use the configuration parameters which this extension provides. 563 | 564 | ### pg_cheat_funcs.log_memory_context (boolean) 565 | Cause statistics about the memory contexts to be logged at the end of query execution. 566 | For details of log format, please see [pg_stat_print_memory_context()](#void-pg_stat_print_memory_context) 567 | This parameter is off by default. Only superusers can change this setting. 568 | 569 | ### pg_cheat_funcs.hide_appname (boolean) 570 | If true, client's application_name is ignored and its setting value is 571 | stored in pg_cheat_funcs.hidden_appname parameter. 572 | By default, this is set to false, so that the string that client specifies 573 | will be used as application_name. 574 | This parameter can only be set in the postgresql.conf 575 | file or on the server command line. 576 | 577 | ### pg_cheat_funcs.hidden_appname (string) 578 | Report client's application_name hidden from view. 579 | The default is an empty string. 580 | Any users can change this setting. 581 | 582 | ### pg_cheat_funcs.log_session_start_options (boolean) 583 | Log options sent to the server at connection start. 584 | This parameter is off by default. 585 | Only superusers (in PostgreSQL 9.5 or later) or any users (in 9.4 or before) 586 | can change this parameter at session start, 587 | and it cannot be changed at all within a session. 588 | 589 | ### pg_cheat_funcs.scheduling_priority (integer) 590 | Specify the scheduling priority ("nice") of PostgreSQL server process. 591 | Valid values are between -20 and 19. 592 | Lower values cause more favorable scheduling. 593 | The default value is zero. 594 | Any users can change this setting. 595 | See getpriority(2) man page for details about a scheduling priority. 596 | 597 | ### pg_cheat_funcs.exit_on_segv (boolean) 598 | If off, which is the default, segmentation fault will lead to the server crash. 599 | If on, only the current session causing segmentation fault will be terminated. 600 | Any users can change this setting. 601 | -------------------------------------------------------------------------------- /conv/euc_jp_to_utf8.extra: -------------------------------------------------------------------------------- 1 | #include "mb/pg_wchar.h" 2 | 3 | #if PG_VERSION_NUM >= 100000 4 | /* 5 | * In 10, commit aeed17d changed character encoding conversions 6 | * so that they use radix tree-based map. As a side effect of this, 7 | * the structure for local code to UTF-8 conversion map, 8 | * pg_local_to_utf, was removed from PostgreSQL source tree 9 | * though it's still necessary for this extra conversion map. 10 | * Therefore we reintroduce pg_local_to_utf structure here. 11 | * 12 | * XXX should this extra conversion map be converted into 13 | * radix tree-based one? 14 | */ 15 | typedef struct 16 | { 17 | uint32 code; /* local code */ 18 | uint32 utf; /* UTF-8 */ 19 | } pg_local_to_utf; 20 | #endif 21 | 22 | static const pg_local_to_utf ExtraLUmapEUC_JP[] = { 23 | {0xf9a1, 0xe7ba8a}, 24 | {0xf9a2, 0xe8a49c}, 25 | {0xf9a3, 0xe98d88}, 26 | {0xf9a4, 0xe98a88}, 27 | {0xf9a5, 0xe8939c}, 28 | {0xf9a6, 0xe4bf89}, 29 | {0xf9a7, 0xe782bb}, 30 | {0xf9a8, 0xe698b1}, 31 | {0xf9a9, 0xe6a388}, 32 | {0xf9aa, 0xe98bb9}, 33 | {0xf9ab, 0xe69bbb}, 34 | {0xf9ac, 0xe5bd85}, 35 | {0xf9ad, 0xe4b8a8}, 36 | {0xf9ae, 0xe4bba1}, 37 | {0xf9af, 0xe4bbbc}, 38 | {0xf9b0, 0xe4bc80}, 39 | {0xf9b1, 0xe4bc83}, 40 | {0xf9b2, 0xe4bcb9}, 41 | {0xf9b3, 0xe4bd96}, 42 | {0xf9b4, 0xe4be92}, 43 | {0xf9b5, 0xe4be8a}, 44 | {0xf9b6, 0xe4be9a}, 45 | {0xf9b7, 0xe4be94}, 46 | {0xf9b8, 0xe4bf8d}, 47 | {0xf9b9, 0xe58180}, 48 | {0xf9ba, 0xe580a2}, 49 | {0xf9bb, 0xe4bfbf}, 50 | {0xf9bc, 0xe5809e}, 51 | {0xf9bd, 0xe58186}, 52 | {0xf9be, 0xe581b0}, 53 | {0xf9bf, 0xe58182}, 54 | {0xf9c0, 0xe58294}, 55 | {0xf9c1, 0xe583b4}, 56 | {0xf9c2, 0xe58398}, 57 | {0xf9c3, 0xe5858a}, 58 | {0xf9c4, 0xe585a4}, 59 | {0xf9c5, 0xe5869d}, 60 | {0xf9c6, 0xe586be}, 61 | {0xf9c7, 0xe587ac}, 62 | {0xf9c8, 0xe58895}, 63 | {0xf9c9, 0xe58a9c}, 64 | {0xf9ca, 0xe58aa6}, 65 | {0xf9cb, 0xe58b80}, 66 | {0xf9cc, 0xe58b9b}, 67 | {0xf9cd, 0xe58c80}, 68 | {0xf9ce, 0xe58c87}, 69 | {0xf9cf, 0xe58ca4}, 70 | {0xf9d0, 0xe58db2}, 71 | {0xf9d1, 0xe58e93}, 72 | {0xf9d2, 0xe58eb2}, 73 | {0xf9d3, 0xe58f9d}, 74 | {0xf9d4, 0xefa88e}, 75 | {0xf9d5, 0xe5929c}, 76 | {0xf9d6, 0xe5928a}, 77 | {0xf9d7, 0xe592a9}, 78 | {0xf9d8, 0xe593bf}, 79 | {0xf9d9, 0xe59686}, 80 | {0xf9da, 0xe59d99}, 81 | {0xf9db, 0xe59da5}, 82 | {0xf9dc, 0xe59eac}, 83 | {0xf9dd, 0xe59f88}, 84 | {0xf9de, 0xe59f87}, 85 | {0xf9df, 0xefa88f}, 86 | {0xf9e0, 0xefa890}, 87 | {0xf9e1, 0xe5a29e}, 88 | {0xf9e2, 0xe5a2b2}, 89 | {0xf9e3, 0xe5a48b}, 90 | {0xf9e4, 0xe5a593}, 91 | {0xf9e5, 0xe5a59b}, 92 | {0xf9e6, 0xe5a59d}, 93 | {0xf9e7, 0xe5a5a3}, 94 | {0xf9e8, 0xe5a6a4}, 95 | {0xf9e9, 0xe5a6ba}, 96 | {0xf9ea, 0xe5ad96}, 97 | {0xf9eb, 0xe5af80}, 98 | {0xf9ec, 0xe794af}, 99 | {0xf9ed, 0xe5af98}, 100 | {0xf9ee, 0xe5afac}, 101 | {0xf9ef, 0xe5b09e}, 102 | {0xf9f0, 0xe5b2a6}, 103 | {0xf9f1, 0xe5b2ba}, 104 | {0xf9f2, 0xe5b3b5}, 105 | {0xf9f3, 0xe5b4a7}, 106 | {0xf9f4, 0xe5b593}, 107 | {0xf9f5, 0xefa891}, 108 | {0xf9f6, 0xe5b582}, 109 | {0xf9f7, 0xe5b5ad}, 110 | {0xf9f8, 0xe5b6b8}, 111 | {0xf9f9, 0xe5b6b9}, 112 | {0xf9fa, 0xe5b790}, 113 | {0xf9fb, 0xe5bca1}, 114 | {0xf9fc, 0xe5bcb4}, 115 | {0xf9fd, 0xe5bda7}, 116 | {0xf9fe, 0xe5beb7}, 117 | {0xfaa1, 0xe5bf9e}, 118 | {0xfaa2, 0xe6819d}, 119 | {0xfaa3, 0xe68285}, 120 | {0xfaa4, 0xe6828a}, 121 | {0xfaa5, 0xe6839e}, 122 | {0xfaa6, 0xe68395}, 123 | {0xfaa7, 0xe684a0}, 124 | {0xfaa8, 0xe683b2}, 125 | {0xfaa9, 0xe68491}, 126 | {0xfaaa, 0xe684b7}, 127 | {0xfaab, 0xe684b0}, 128 | {0xfaac, 0xe68698}, 129 | {0xfaad, 0xe68893}, 130 | {0xfaae, 0xe68aa6}, 131 | {0xfaaf, 0xe68fb5}, 132 | {0xfab0, 0xe691a0}, 133 | {0xfab1, 0xe6929d}, 134 | {0xfab2, 0xe6938e}, 135 | {0xfab3, 0xe6958e}, 136 | {0xfab4, 0xe69880}, 137 | {0xfab5, 0xe69895}, 138 | {0xfab6, 0xe698bb}, 139 | {0xfab7, 0xe69889}, 140 | {0xfab8, 0xe698ae}, 141 | {0xfab9, 0xe6989e}, 142 | {0xfaba, 0xe698a4}, 143 | {0xfabb, 0xe699a5}, 144 | {0xfabc, 0xe69997}, 145 | {0xfabd, 0xe69999}, 146 | {0xfabe, 0xefa892}, 147 | {0xfabf, 0xe699b3}, 148 | {0xfac0, 0xe69a99}, 149 | {0xfac1, 0xe69aa0}, 150 | {0xfac2, 0xe69ab2}, 151 | {0xfac3, 0xe69abf}, 152 | {0xfac4, 0xe69bba}, 153 | {0xfac5, 0xe69c8e}, 154 | {0xfac6, 0xefa4a9}, 155 | {0xfac7, 0xe69da6}, 156 | {0xfac8, 0xe69ebb}, 157 | {0xfac9, 0xe6a192}, 158 | {0xfaca, 0xe69f80}, 159 | {0xfacb, 0xe6a081}, 160 | {0xfacc, 0xe6a184}, 161 | {0xfacd, 0xe6a38f}, 162 | {0xface, 0xefa893}, 163 | {0xfacf, 0xe6a5a8}, 164 | {0xfad0, 0xefa894}, 165 | {0xfad1, 0xe6a698}, 166 | {0xfad2, 0xe6a7a2}, 167 | {0xfad3, 0xe6a8b0}, 168 | {0xfad4, 0xe6a9ab}, 169 | {0xfad5, 0xe6a986}, 170 | {0xfad6, 0xe6a9b3}, 171 | {0xfad7, 0xe6a9be}, 172 | {0xfad8, 0xe6aba2}, 173 | {0xfad9, 0xe6aba4}, 174 | {0xfada, 0xe6af96}, 175 | {0xfadb, 0xe6b0bf}, 176 | {0xfadc, 0xe6b19c}, 177 | {0xfadd, 0xe6b286}, 178 | {0xfade, 0xe6b1af}, 179 | {0xfadf, 0xe6b39a}, 180 | {0xfae0, 0xe6b484}, 181 | {0xfae1, 0xe6b687}, 182 | {0xfae2, 0xe6b5af}, 183 | {0xfae3, 0xe6b696}, 184 | {0xfae4, 0xe6b6ac}, 185 | {0xfae5, 0xe6b78f}, 186 | {0xfae6, 0xe6b7b8}, 187 | {0xfae7, 0xe6b7b2}, 188 | {0xfae8, 0xe6b7bc}, 189 | {0xfae9, 0xe6b8b9}, 190 | {0xfaea, 0xe6b99c}, 191 | {0xfaeb, 0xe6b8a7}, 192 | {0xfaec, 0xe6b8bc}, 193 | {0xfaed, 0xe6babf}, 194 | {0xfaee, 0xe6be88}, 195 | {0xfaef, 0xe6beb5}, 196 | {0xfaf0, 0xe6bfb5}, 197 | {0xfaf1, 0xe78085}, 198 | {0xfaf2, 0xe78087}, 199 | {0xfaf3, 0xe780a8}, 200 | {0xfaf4, 0xe78285}, 201 | {0xfaf5, 0xe782ab}, 202 | {0xfaf6, 0xe7848f}, 203 | {0xfaf7, 0xe78484}, 204 | {0xfaf8, 0xe7859c}, 205 | {0xfaf9, 0xe78586}, 206 | {0xfafa, 0xe78587}, 207 | {0xfafb, 0xefa895}, 208 | {0xfafc, 0xe78781}, 209 | {0xfafd, 0xe787be}, 210 | {0xfafe, 0xe78ab1}, 211 | {0xfba1, 0xe78abe}, 212 | {0xfba2, 0xe78ca4}, 213 | {0xfba3, 0xefa896}, 214 | {0xfba4, 0xe78db7}, 215 | {0xfba5, 0xe78ebd}, 216 | {0xfba6, 0xe78f89}, 217 | {0xfba7, 0xe78f96}, 218 | {0xfba8, 0xe78fa3}, 219 | {0xfba9, 0xe78f92}, 220 | {0xfbaa, 0xe79087}, 221 | {0xfbab, 0xe78fb5}, 222 | {0xfbac, 0xe790a6}, 223 | {0xfbad, 0xe790aa}, 224 | {0xfbae, 0xe790a9}, 225 | {0xfbaf, 0xe790ae}, 226 | {0xfbb0, 0xe791a2}, 227 | {0xfbb1, 0xe79289}, 228 | {0xfbb2, 0xe7929f}, 229 | {0xfbb3, 0xe79481}, 230 | {0xfbb4, 0xe795af}, 231 | {0xfbb5, 0xe79a82}, 232 | {0xfbb6, 0xe79a9c}, 233 | {0xfbb7, 0xe79a9e}, 234 | {0xfbb8, 0xe79a9b}, 235 | {0xfbb9, 0xe79aa6}, 236 | {0xfbba, 0xefa897}, 237 | {0xfbbb, 0xe79d86}, 238 | {0xfbbc, 0xe58aaf}, 239 | {0xfbbd, 0xe7a0a1}, 240 | {0xfbbe, 0xe7a18e}, 241 | {0xfbbf, 0xe7a1a4}, 242 | {0xfbc0, 0xe7a1ba}, 243 | {0xfbc1, 0xe7a4b0}, 244 | {0xfbc2, 0xefa898}, 245 | {0xfbc3, 0xefa899}, 246 | {0xfbc4, 0xefa89a}, 247 | {0xfbc5, 0xe7a694}, 248 | {0xfbc6, 0xefa89b}, 249 | {0xfbc7, 0xe7a69b}, 250 | {0xfbc8, 0xe7ab91}, 251 | {0xfbc9, 0xe7aba7}, 252 | {0xfbca, 0xefa89c}, 253 | {0xfbcb, 0xe7abab}, 254 | {0xfbcc, 0xe7ae9e}, 255 | {0xfbcd, 0xefa89d}, 256 | {0xfbce, 0xe7b588}, 257 | {0xfbcf, 0xe7b59c}, 258 | {0xfbd0, 0xe7b6b7}, 259 | {0xfbd1, 0xe7b6a0}, 260 | {0xfbd2, 0xe7b796}, 261 | {0xfbd3, 0xe7b992}, 262 | {0xfbd4, 0xe7bd87}, 263 | {0xfbd5, 0xe7bea1}, 264 | {0xfbd6, 0xefa89e}, 265 | {0xfbd7, 0xe88c81}, 266 | {0xfbd8, 0xe88da2}, 267 | {0xfbd9, 0xe88dbf}, 268 | {0xfbda, 0xe88f87}, 269 | {0xfbdb, 0xe88fb6}, 270 | {0xfbdc, 0xe89188}, 271 | {0xfbdd, 0xe892b4}, 272 | {0xfbde, 0xe89593}, 273 | {0xfbdf, 0xe89599}, 274 | {0xfbe0, 0xe895ab}, 275 | {0xfbe1, 0xefa89f}, 276 | {0xfbe2, 0xe896b0}, 277 | {0xfbe3, 0xefa8a0}, 278 | {0xfbe4, 0xefa8a1}, 279 | {0xfbe5, 0xe8a087}, 280 | {0xfbe6, 0xe8a3b5}, 281 | {0xfbe7, 0xe8a892}, 282 | {0xfbe8, 0xe8a8b7}, 283 | {0xfbe9, 0xe8a9b9}, 284 | {0xfbea, 0xe8aaa7}, 285 | {0xfbeb, 0xe8aabe}, 286 | {0xfbec, 0xe8ab9f}, 287 | {0xfbed, 0xefa8a2}, 288 | {0xfbee, 0xe8abb6}, 289 | {0xfbef, 0xe8ad93}, 290 | {0xfbf0, 0xe8adbf}, 291 | {0xfbf1, 0xe8b3b0}, 292 | {0xfbf2, 0xe8b3b4}, 293 | {0xfbf3, 0xe8b492}, 294 | {0xfbf4, 0xe8b5b6}, 295 | {0xfbf5, 0xefa8a3}, 296 | {0xfbf6, 0xe8bb8f}, 297 | {0xfbf7, 0xefa8a4}, 298 | {0xfbf8, 0xefa8a5}, 299 | {0xfbf9, 0xe981a7}, 300 | {0xfbfa, 0xe9839e}, 301 | {0xfbfb, 0xefa8a6}, 302 | {0xfbfc, 0xe98495}, 303 | {0xfbfd, 0xe984a7}, 304 | {0xfbfe, 0xe9879a}, 305 | {0xfca1, 0xe98797}, 306 | {0xfca2, 0xe9879e}, 307 | {0xfca3, 0xe987ad}, 308 | {0xfca4, 0xe987ae}, 309 | {0xfca5, 0xe987a4}, 310 | {0xfca6, 0xe987a5}, 311 | {0xfca7, 0xe98886}, 312 | {0xfca8, 0xe98890}, 313 | {0xfca9, 0xe9888a}, 314 | {0xfcaa, 0xe988ba}, 315 | {0xfcab, 0xe98980}, 316 | {0xfcac, 0xe988bc}, 317 | {0xfcad, 0xe9898e}, 318 | {0xfcae, 0xe98999}, 319 | {0xfcaf, 0xe98991}, 320 | {0xfcb0, 0xe988b9}, 321 | {0xfcb1, 0xe989a7}, 322 | {0xfcb2, 0xe98aa7}, 323 | {0xfcb3, 0xe989b7}, 324 | {0xfcb4, 0xe989b8}, 325 | {0xfcb5, 0xe98ba7}, 326 | {0xfcb6, 0xe98b97}, 327 | {0xfcb7, 0xe98b99}, 328 | {0xfcb8, 0xe98b90}, 329 | {0xfcb9, 0xefa8a7}, 330 | {0xfcba, 0xe98b95}, 331 | {0xfcbb, 0xe98ba0}, 332 | {0xfcbc, 0xe98b93}, 333 | {0xfcbd, 0xe98ca5}, 334 | {0xfcbe, 0xe98ca1}, 335 | {0xfcbf, 0xe98bbb}, 336 | {0xfcc0, 0xefa8a8}, 337 | {0xfcc1, 0xe98c9e}, 338 | {0xfcc2, 0xe98bbf}, 339 | {0xfcc3, 0xe98c9d}, 340 | {0xfcc4, 0xe98c82}, 341 | {0xfcc5, 0xe98db0}, 342 | {0xfcc6, 0xe98d97}, 343 | {0xfcc7, 0xe98ea4}, 344 | {0xfcc8, 0xe98f86}, 345 | {0xfcc9, 0xe98f9e}, 346 | {0xfcca, 0xe98fb8}, 347 | {0xfccb, 0xe990b1}, 348 | {0xfccc, 0xe99185}, 349 | {0xfccd, 0xe99188}, 350 | {0xfcce, 0xe99692}, 351 | {0xfccf, 0xefa79c}, 352 | {0xfcd0, 0xefa8a9}, 353 | {0xfcd1, 0xe99a9d}, 354 | {0xfcd2, 0xe99aaf}, 355 | {0xfcd3, 0xe99cb3}, 356 | {0xfcd4, 0xe99cbb}, 357 | {0xfcd5, 0xe99d83}, 358 | {0xfcd6, 0xe99d8d}, 359 | {0xfcd7, 0xe99d8f}, 360 | {0xfcd8, 0xe99d91}, 361 | {0xfcd9, 0xe99d95}, 362 | {0xfcda, 0xe9a197}, 363 | {0xfcdb, 0xe9a1a5}, 364 | {0xfcdc, 0xefa8aa}, 365 | {0xfcdd, 0xefa8ab}, 366 | {0xfcde, 0xe9a4a7}, 367 | {0xfcdf, 0xefa8ac}, 368 | {0xfce0, 0xe9a69e}, 369 | {0xfce1, 0xe9a98e}, 370 | {0xfce2, 0xe9ab99}, 371 | {0xfce3, 0xe9ab9c}, 372 | {0xfce4, 0xe9adb5}, 373 | {0xfce5, 0xe9adb2}, 374 | {0xfce6, 0xe9ae8f}, 375 | {0xfce7, 0xe9aeb1}, 376 | {0xfce8, 0xe9aebb}, 377 | {0xfce9, 0xe9b080}, 378 | {0xfcea, 0xe9b5b0}, 379 | {0xfceb, 0xe9b5ab}, 380 | {0xfcec, 0xefa8ad}, 381 | {0xfced, 0xe9b899}, 382 | {0xfcee, 0xe9bb91}, 383 | {0xfcf1, 0xe285b0}, 384 | {0xfcf2, 0xe285b1}, 385 | {0xfcf3, 0xe285b2}, 386 | {0xfcf4, 0xe285b3}, 387 | {0xfcf5, 0xe285b4}, 388 | {0xfcf6, 0xe285b5}, 389 | {0xfcf7, 0xe285b6}, 390 | {0xfcf8, 0xe285b7}, 391 | {0xfcf9, 0xe285b8}, 392 | {0xfcfa, 0xe285b9}, 393 | {0xfcfb, 0xefbfa2}, 394 | {0xfcfc, 0xefbfa4}, 395 | {0xfcfd, 0xefbc87}, 396 | {0xfcfe, 0xefbc82}, 397 | {0x8fa2b7, 0xefbd9e}, 398 | }; 399 | -------------------------------------------------------------------------------- /expected/pg_94_or_later.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | CREATE TABLE test_lsn (lsn pg_lsn); 4 | INSERT INTO test_lsn VALUES ('0/A'), ('0/1000'), ('DA3/15A4D10'), ('E4/A0422B68'), ('447/F6D166E8'); 5 | SELECT min(lsn), max(lsn) FROM test_lsn; 6 | min | max 7 | -----+------------- 8 | 0/A | DA3/15A4D10 9 | (1 row) 10 | 11 | SELECT pg_file_fsync('global'); 12 | pg_file_fsync 13 | --------------- 14 | 15 | (1 row) 16 | 17 | SELECT pg_file_fsync('global/pg_control'); 18 | pg_file_fsync 19 | --------------- 20 | 21 | (1 row) 22 | 23 | BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; 24 | SELECT pg_refresh_snapshot(); 25 | pg_refresh_snapshot 26 | --------------------- 27 | 28 | (1 row) 29 | 30 | SELECT 1; 31 | ?column? 32 | ---------- 33 | 1 34 | (1 row) 35 | 36 | SELECT pg_refresh_snapshot(); 37 | pg_refresh_snapshot 38 | --------------------- 39 | 40 | (1 row) 41 | 42 | COMMIT; 43 | DROP EXTENSION pg_cheat_funcs; 44 | -------------------------------------------------------------------------------- /expected/pg_advance_vacuum_cleanup_age.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | DO $$ 4 | DECLARE 5 | orig_cleanup_age text := current_setting('vacuum_defer_cleanup_age'); 6 | BEGIN 7 | PERFORM pg_advance_vacuum_cleanup_age(99); 8 | IF current_setting('vacuum_defer_cleanup_age') <> '-99' THEN 9 | RAISE WARNING 'could not advance vacuum cleanup age properly.'; 10 | END IF; 11 | PERFORM pg_advance_vacuum_cleanup_age(); 12 | IF current_setting('vacuum_defer_cleanup_age') <> orig_cleanup_age THEN 13 | RAISE NOTICE 'could not reset vacuum cleanup age properly.'; 14 | END IF; 15 | END; 16 | $$ LANGUAGE plpgsql; 17 | DROP EXTENSION pg_cheat_funcs; 18 | -------------------------------------------------------------------------------- /expected/pg_cached_plan.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | PREPARE stmt AS SELECT * FROM pg_database WHERE datname = $1; 4 | SELECT * FROM pg_cached_plan_source('stmt'); 5 | generic_cost | total_custom_cost | num_custom_plans | force_generic | force_custom 6 | --------------+-------------------+------------------+---------------+-------------- 7 | -1 | 0 | 0 | f | f 8 | (1 row) 9 | 10 | DROP EXTENSION pg_cheat_funcs; 11 | -------------------------------------------------------------------------------- /expected/pg_cheat_funcs.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | SELECT pg_signal_process(pg_postmaster_pid(), 'HUP'); 4 | pg_signal_process 5 | ------------------- 6 | 7 | (1 row) 8 | 9 | SET pg_cheat_funcs.scheduling_priority TO 1; 10 | SELECT pg_get_priority(pg_backend_pid()); 11 | pg_get_priority 12 | ----------------- 13 | 1 14 | (1 row) 15 | 16 | SELECT pg_set_priority(pg_backend_pid(), 2); 17 | pg_set_priority 18 | ----------------- 19 | 20 | (1 row) 21 | 22 | SHOW pg_cheat_funcs.scheduling_priority; 23 | pg_cheat_funcs.scheduling_priority 24 | ------------------------------------ 25 | 2 26 | (1 row) 27 | 28 | SELECT pg_eucjp('xa4', 'xa2'); 29 | ERROR: database encoding is UTF8 30 | HINT: pg_eucjp() can be executed only under EUC_JP encoding. 31 | SELECT pg_set_next_xid(next_xid) = next_xid FROM pg_xid_assignment(); 32 | ?column? 33 | ---------- 34 | t 35 | (1 row) 36 | 37 | SELECT to_octal(num) FROM generate_series(1, 10) num; 38 | to_octal 39 | ---------- 40 | 1 41 | 2 42 | 3 43 | 4 44 | 5 45 | 6 46 | 7 47 | 10 48 | 11 49 | 12 50 | (10 rows) 51 | 52 | SELECT to_octal(2147483647::integer); 53 | to_octal 54 | ------------- 55 | 17777777777 56 | (1 row) 57 | 58 | SELECT to_octal(9223372036854775807::bigint); 59 | to_octal 60 | ----------------------- 61 | 777777777777777777777 62 | (1 row) 63 | 64 | SELECT pg_text_to_hex('PostgreSQL'); 65 | pg_text_to_hex 66 | ---------------------- 67 | 506f737467726553514c 68 | (1 row) 69 | 70 | SELECT pg_hex_to_text('506f737467726553514c'); 71 | pg_hex_to_text 72 | ---------------- 73 | PostgreSQL 74 | (1 row) 75 | 76 | SELECT pg_hex_to_text(upper('506f737467726553514c')); 77 | pg_hex_to_text 78 | ---------------- 79 | PostgreSQL 80 | (1 row) 81 | 82 | SELECT pg_backend_start_time() = backend_start FROM pg_stat_get_activity(pg_backend_pid()); 83 | ?column? 84 | ---------- 85 | t 86 | (1 row) 87 | 88 | SELECT substring(pg_tablespace_version_directory(), 1, 3); 89 | substring 90 | ----------- 91 | PG_ 92 | (1 row) 93 | 94 | BEGIN; 95 | SELECT pg_advisory_xact_lock(111); 96 | pg_advisory_xact_lock 97 | ----------------------- 98 | 99 | (1 row) 100 | 101 | SELECT pg_advisory_xact_lock(222); 102 | pg_advisory_xact_lock 103 | ----------------------- 104 | 105 | (1 row) 106 | 107 | SELECT pg_advisory_xact_lock_shared(333); 108 | pg_advisory_xact_lock_shared 109 | ------------------------------ 110 | 111 | (1 row) 112 | 113 | SELECT pg_advisory_xact_lock(444, 555); 114 | pg_advisory_xact_lock 115 | ----------------------- 116 | 117 | (1 row) 118 | 119 | SELECT pg_advisory_xact_lock_shared(666, 777); 120 | pg_advisory_xact_lock_shared 121 | ------------------------------ 122 | 123 | (1 row) 124 | 125 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 126 | classid | objid | objsubid | mode 127 | ---------+-------+----------+--------------- 128 | 0 | 111 | 1 | ExclusiveLock 129 | 0 | 222 | 1 | ExclusiveLock 130 | 0 | 333 | 1 | ShareLock 131 | 444 | 555 | 2 | ExclusiveLock 132 | 666 | 777 | 2 | ShareLock 133 | (5 rows) 134 | 135 | SELECT pg_advisory_xact_unlock(111); 136 | pg_advisory_xact_unlock 137 | ------------------------- 138 | t 139 | (1 row) 140 | 141 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 142 | classid | objid | objsubid | mode 143 | ---------+-------+----------+--------------- 144 | 0 | 222 | 1 | ExclusiveLock 145 | 0 | 333 | 1 | ShareLock 146 | 444 | 555 | 2 | ExclusiveLock 147 | 666 | 777 | 2 | ShareLock 148 | (4 rows) 149 | 150 | SELECT pg_advisory_xact_unlock_shared(666, 777); 151 | pg_advisory_xact_unlock_shared 152 | -------------------------------- 153 | t 154 | (1 row) 155 | 156 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 157 | classid | objid | objsubid | mode 158 | ---------+-------+----------+--------------- 159 | 0 | 222 | 1 | ExclusiveLock 160 | 0 | 333 | 1 | ShareLock 161 | 444 | 555 | 2 | ExclusiveLock 162 | (3 rows) 163 | 164 | COMMIT; 165 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 166 | classid | objid | objsubid | mode 167 | ---------+-------+----------+------ 168 | (0 rows) 169 | 170 | -- SET pg_cheat_funcs.exit_on_segv TO on; 171 | -- SELECT pg_segmentation_fault(true); 172 | -- SET pg_cheat_funcs.exit_on_segv TO off; 173 | DROP EXTENSION pg_cheat_funcs; 174 | -------------------------------------------------------------------------------- /expected/pg_chr.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | SELECT chr(88) = pg_chr(88); 4 | ?column? 5 | ---------- 6 | t 7 | (1 row) 8 | 9 | SELECT chr(12354) = pg_chr(12354); 10 | ?column? 11 | ---------- 12 | t 13 | (1 row) 14 | 15 | SELECT chr(57000); 16 | ERROR: requested character not valid for encoding: 57000 17 | SELECT pg_chr(57000); 18 | pg_chr 19 | -------- 20 | (null) 21 | (1 row) 22 | 23 | SELECT chr(2000000); 24 | ERROR: requested character too large for encoding: 2000000 25 | SELECT pg_chr(2000000); 26 | pg_chr 27 | -------- 28 | (null) 29 | (1 row) 30 | 31 | SELECT pg_chr(code) FROM generate_series(57000, 57010) code; 32 | pg_chr 33 | -------- 34 | (null) 35 | (null) 36 | (null) 37 | (null) 38 | (null) 39 | (null) 40 | (null) 41 | (null) 42 | (null) 43 | (null) 44 | (null) 45 | (11 rows) 46 | 47 | DROP EXTENSION pg_cheat_funcs; 48 | -------------------------------------------------------------------------------- /expected/pg_chr_91_93.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasaoFujii/pg_cheat_funcs/0c1a9e10823a6db6d40cded37a021a7b474c3333/expected/pg_chr_91_93.out -------------------------------------------------------------------------------- /expected/pg_eucjp.out: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MasaoFujii/pg_cheat_funcs/0c1a9e10823a6db6d40cded37a021a7b474c3333/expected/pg_eucjp.out -------------------------------------------------------------------------------- /expected/pg_saslprep.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | SELECT pg_saslprep(chr(8470) || chr(9316) || '4' || chr(12892)); 4 | pg_saslprep 5 | ------------- 6 | No5432 7 | (1 row) 8 | 9 | DROP EXTENSION pg_cheat_funcs; 10 | -------------------------------------------------------------------------------- /expected/pg_stat_get_memory_context.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | SELECT name FROM pg_stat_get_memory_context() WHERE parent IS NULL; 4 | name 5 | ------------------ 6 | TopMemoryContext 7 | (1 row) 8 | 9 | DROP EXTENSION pg_cheat_funcs; 10 | -------------------------------------------------------------------------------- /expected/pg_stat_print_memory_context.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | SELECT pg_stat_print_memory_context(); 4 | pg_stat_print_memory_context 5 | ------------------------------ 6 | 7 | (1 row) 8 | 9 | DROP EXTENSION pg_cheat_funcs; 10 | -------------------------------------------------------------------------------- /expected/pg_xid_to_xid8.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | BEGIN; 4 | SELECT 1 FROM pg_current_xact_id(); 5 | ?column? 6 | ---------- 7 | 1 8 | (1 row) 9 | 10 | SELECT pg_current_xact_id() = pg_xid_to_xid8(backend_xid) 11 | FROM pg_stat_activity WHERE pid = pg_backend_pid(); 12 | ?column? 13 | ---------- 14 | t 15 | (1 row) 16 | 17 | COMMIT; 18 | DROP EXTENSION pg_cheat_funcs; 19 | -------------------------------------------------------------------------------- /expected/pglz_compress.out: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | \pset null '(null)' 3 | SELECT lz, aa, pglz_decompress(lz), aa::bytea, pglz_decompress_bytea(lz) 4 | FROM (SELECT aa, pglz_compress(aa) lz FROM repeat('A', 2) aa) hoge; 5 | lz | aa | pglz_decompress | aa | pglz_decompress_bytea 6 | ----------------+----+-----------------+--------+----------------------- 7 | \x020000004141 | AA | AA | \x4141 | \x4141 8 | (1 row) 9 | 10 | SELECT lz, aa, pglz_decompress(lz), aa::bytea, pglz_decompress_bytea(lz) 11 | FROM (SELECT aa, pglz_compress(aa) lz FROM repeat('A', 32) aa) hoge; 12 | lz | aa | pglz_decompress | aa | pglz_decompress_bytea 13 | ----------------------+----------------------------------+----------------------------------+--------------------------------------------------------------------+-------------------------------------------------------------------- 14 | \x2000004002410f010d | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | \x4141414141414141414141414141414141414141414141414141414141414141 | \x4141414141414141414141414141414141414141414141414141414141414141 15 | (1 row) 16 | 17 | SELECT lz, aa, pglz_decompress_bytea(lz), pglz_decompress(lz) 18 | FROM (SELECT aa::bytea, pglz_compress_bytea(aa::bytea) lz FROM repeat('A', 2) aa) hoge; 19 | lz | aa | pglz_decompress_bytea | pglz_decompress 20 | ----------------+--------+-----------------------+----------------- 21 | \x020000004141 | \x4141 | \x4141 | AA 22 | (1 row) 23 | 24 | SELECT lz, aa, pglz_decompress_bytea(lz), pglz_decompress(lz) 25 | FROM (SELECT aa::bytea, pglz_compress_bytea(aa::bytea) lz FROM repeat('A', 32) aa) hoge; 26 | lz | aa | pglz_decompress_bytea | pglz_decompress 27 | ----------------------+--------------------------------------------------------------------+--------------------------------------------------------------------+---------------------------------- 28 | \x2000004002410f010d | \x4141414141414141414141414141414141414141414141414141414141414141 | \x4141414141414141414141414141414141414141414141414141414141414141 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA 29 | (1 row) 30 | 31 | DROP EXTENSION pg_cheat_funcs; 32 | -------------------------------------------------------------------------------- /pg_cheat_funcs--1.0.sql: -------------------------------------------------------------------------------- 1 | -- complain if script is sourced in psql, rather than via CREATE EXTENSION 2 | \echo Use "CREATE EXTENSION pg_cheat_funcs" to load this file. \quit 3 | 4 | -- pg_stat_get_memory_context function is available only in between 9.6 and 13 5 | DO $$ 6 | DECLARE 7 | pgversion INTEGER; 8 | BEGIN 9 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 10 | IF pgversion >= 90600 AND pgversion < 140000 THEN 11 | CREATE FUNCTION pg_stat_get_memory_context(OUT name text, 12 | OUT parent text, 13 | OUT level integer, 14 | OUT total_bytes bigint, 15 | OUT total_nblocks bigint, 16 | OUT free_bytes bigint, 17 | OUT free_chunks bigint, 18 | OUT used_bytes bigint) 19 | RETURNS SETOF record 20 | AS 'MODULE_PATHNAME' 21 | LANGUAGE C STRICT VOLATILE; 22 | REVOKE ALL ON FUNCTION pg_stat_get_memory_context() FROM PUBLIC; 23 | END IF; 24 | END; 25 | $$; 26 | 27 | -- pg_stat_print_memory_context function is available only in 13 or before 28 | DO $$ 29 | DECLARE 30 | pgversion INTEGER; 31 | BEGIN 32 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 33 | IF pgversion < 140000 THEN 34 | CREATE FUNCTION pg_stat_print_memory_context() 35 | RETURNS void 36 | AS 'MODULE_PATHNAME' 37 | LANGUAGE C STRICT VOLATILE; 38 | REVOKE ALL ON FUNCTION pg_stat_print_memory_context() FROM PUBLIC; 39 | END IF; 40 | END; 41 | $$; 42 | 43 | /* pg_cached_plan_source function is available only in 9.2 or later */ 44 | DO $$ 45 | DECLARE 46 | pgversion INTEGER; 47 | BEGIN 48 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 49 | IF pgversion >= 90200 THEN 50 | CREATE FUNCTION pg_cached_plan_source(IN stmt text, 51 | OUT generic_cost double precision, 52 | OUT total_custom_cost double precision, 53 | OUT num_custom_plans integer, 54 | OUT force_generic boolean, 55 | OUT force_custom boolean) 56 | RETURNS record 57 | AS 'MODULE_PATHNAME' 58 | LANGUAGE C STRICT VOLATILE; 59 | END IF; 60 | END; 61 | $$; 62 | 63 | CREATE FUNCTION pg_signal_process(integer, text) 64 | RETURNS void 65 | AS 'MODULE_PATHNAME' 66 | LANGUAGE C STRICT VOLATILE; 67 | REVOKE ALL ON FUNCTION pg_signal_process(integer, text) FROM PUBLIC; 68 | 69 | CREATE FUNCTION pg_get_priority(integer) 70 | RETURNS integer 71 | AS 'MODULE_PATHNAME' 72 | LANGUAGE C STRICT VOLATILE; 73 | REVOKE ALL ON FUNCTION pg_get_priority(integer) FROM PUBLIC; 74 | 75 | CREATE FUNCTION pg_set_priority(integer, integer) 76 | RETURNS void 77 | AS 'MODULE_PATHNAME' 78 | LANGUAGE C STRICT VOLATILE; 79 | REVOKE ALL ON FUNCTION pg_set_priority(integer, integer) FROM PUBLIC; 80 | 81 | CREATE FUNCTION pg_segmentation_fault(boolean DEFAULT false) 82 | RETURNS void 83 | AS 'MODULE_PATHNAME' 84 | LANGUAGE C STRICT VOLATILE; 85 | REVOKE ALL ON FUNCTION pg_segmentation_fault(boolean) FROM PUBLIC; 86 | 87 | CREATE FUNCTION pg_process_config_file() 88 | RETURNS void 89 | AS 'MODULE_PATHNAME' 90 | LANGUAGE C STRICT VOLATILE; 91 | REVOKE ALL ON FUNCTION pg_process_config_file() FROM PUBLIC; 92 | 93 | /* Any functions using pg_lsn data type are available only in 9.4 or later */ 94 | DO $$ 95 | DECLARE 96 | pgversion INTEGER; 97 | BEGIN 98 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 99 | IF pgversion >= 90400 THEN 100 | -- Use VOLATILE because the heading 8 digits of returned WAL file name 101 | -- (i.e., represents the timeline) can be changed during recovery. 102 | CREATE FUNCTION pg_xlogfile_name(pg_lsn, boolean) 103 | RETURNS text 104 | AS 'MODULE_PATHNAME' 105 | LANGUAGE C STRICT VOLATILE; 106 | 107 | -- Create min() and max() aggregates for pg_lsn in 12 or before. 108 | -- They are supported in core since 13. 109 | IF pgversion < 130000 THEN 110 | CREATE FUNCTION pg_lsn_larger(pg_lsn, pg_lsn) 111 | RETURNS pg_lsn 112 | AS 'MODULE_PATHNAME' 113 | LANGUAGE C STRICT IMMUTABLE; 114 | 115 | CREATE FUNCTION pg_lsn_smaller(pg_lsn, pg_lsn) 116 | RETURNS pg_lsn 117 | AS 'MODULE_PATHNAME' 118 | LANGUAGE C STRICT IMMUTABLE; 119 | 120 | CREATE AGGREGATE max(pg_lsn) ( 121 | SFUNC = pg_lsn_larger, 122 | STYPE = pg_lsn, 123 | SORTOP = > 124 | ); 125 | 126 | CREATE AGGREGATE min(pg_lsn) ( 127 | SFUNC = pg_lsn_smaller, 128 | STYPE = pg_lsn, 129 | SORTOP = < 130 | ); 131 | END IF; 132 | END IF; 133 | END; 134 | $$; 135 | 136 | /* pg_stat_get_syncrep_waiters function is available only in 9.4 or later */ 137 | DO $$ 138 | DECLARE 139 | pgversion INTEGER; 140 | BEGIN 141 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 142 | IF pgversion >= 90400 THEN 143 | CREATE FUNCTION pg_stat_get_syncrep_waiters(OUT pid integer, 144 | OUT wait_lsn pg_lsn, 145 | OUT wait_mode text) 146 | RETURNS SETOF record 147 | AS 'MODULE_PATHNAME' 148 | LANGUAGE C STRICT VOLATILE; 149 | REVOKE ALL ON FUNCTION pg_stat_get_syncrep_waiters() FROM PUBLIC; 150 | END IF; 151 | END; 152 | $$; 153 | 154 | /* pg_wait_syncrep function is available only in 9.4 or later */ 155 | DO $$ 156 | DECLARE 157 | pgversion INTEGER; 158 | BEGIN 159 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 160 | IF pgversion >= 90400 THEN 161 | CREATE FUNCTION pg_wait_syncrep(pg_lsn) 162 | RETURNS void 163 | AS 'MODULE_PATHNAME' 164 | LANGUAGE C STRICT VOLATILE; 165 | REVOKE ALL ON FUNCTION pg_wait_syncrep(pg_lsn) FROM PUBLIC; 166 | END IF; 167 | END; 168 | $$; 169 | 170 | /* pg_refresh_snapshot function is available only in 9.4 or later */ 171 | DO $$ 172 | DECLARE 173 | pgversion INTEGER; 174 | BEGIN 175 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 176 | IF pgversion >= 90400 THEN 177 | CREATE FUNCTION pg_refresh_snapshot() 178 | RETURNS void 179 | AS 'MODULE_PATHNAME' 180 | LANGUAGE C STRICT VOLATILE; 181 | REVOKE ALL ON FUNCTION pg_refresh_snapshot() FROM PUBLIC; 182 | END IF; 183 | END; 184 | $$; 185 | 186 | CREATE FUNCTION pg_set_next_xid(xid) 187 | RETURNS xid 188 | AS 'MODULE_PATHNAME' 189 | LANGUAGE C STRICT VOLATILE; 190 | REVOKE ALL ON FUNCTION pg_set_next_xid(xid) FROM PUBLIC; 191 | 192 | CREATE FUNCTION pg_xid_assignment(OUT next_xid xid, 193 | OUT oldest_xid xid, 194 | OUT xid_vac_limit xid, 195 | OUT xid_warn_limit xid, 196 | OUT xid_stop_limit xid, 197 | OUT xid_wrap_limit xid, 198 | OUT oldest_xid_db oid) 199 | AS 'MODULE_PATHNAME' 200 | LANGUAGE C STRICT VOLATILE; 201 | REVOKE ALL ON FUNCTION pg_xid_assignment() FROM PUBLIC; 202 | 203 | /* pg_xid_to_xid8 function is available only in 13 or later */ 204 | DO $$ 205 | DECLARE 206 | pgversion INTEGER; 207 | BEGIN 208 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 209 | IF pgversion >= 130000 THEN 210 | CREATE FUNCTION pg_xid_to_xid8(xid) 211 | RETURNS xid8 212 | AS 'MODULE_PATHNAME' 213 | LANGUAGE C STRICT VOLATILE; 214 | END IF; 215 | END; 216 | $$; 217 | 218 | CREATE FUNCTION pg_set_next_oid(oid) 219 | RETURNS oid 220 | AS 'MODULE_PATHNAME' 221 | LANGUAGE C STRICT VOLATILE; 222 | REVOKE ALL ON FUNCTION pg_set_next_oid(oid) FROM PUBLIC; 223 | 224 | CREATE FUNCTION pg_oid_assignment(OUT next_oid oid, 225 | OUT oid_count integer) 226 | AS 'MODULE_PATHNAME' 227 | LANGUAGE C STRICT VOLATILE; 228 | REVOKE ALL ON FUNCTION pg_oid_assignment() FROM PUBLIC; 229 | 230 | -- Create pg_advance_vacuum_cleanup_age() only in 15 or earlier, 231 | -- as the vacuum_defer_cleanup_age GUC that it depends on was 232 | -- removed in 16. 233 | DO $$ 234 | DECLARE 235 | pgversion INTEGER; 236 | BEGIN 237 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 238 | IF pgversion < 160000 THEN 239 | CREATE FUNCTION pg_advance_vacuum_cleanup_age(integer DEFAULT NULL) 240 | RETURNS integer 241 | AS 'MODULE_PATHNAME' 242 | LANGUAGE C CALLED ON NULL INPUT VOLATILE; 243 | REVOKE ALL ON FUNCTION pg_advance_vacuum_cleanup_age(integer) FROM PUBLIC; 244 | END IF; 245 | END; 246 | $$; 247 | 248 | CREATE FUNCTION pg_checkpoint(bool DEFAULT true, bool DEFAULT true, 249 | bool DEFAULT true) 250 | RETURNS void 251 | AS 'MODULE_PATHNAME' 252 | LANGUAGE C STRICT VOLATILE; 253 | REVOKE ALL ON FUNCTION pg_checkpoint(bool, bool, bool) FROM PUBLIC; 254 | 255 | -- Create pg_promote() only in 11 or before because it's supported 256 | -- in core since 12. 257 | DO $$ 258 | DECLARE 259 | pgversion INTEGER; 260 | BEGIN 261 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 262 | IF pgversion < 120000 THEN 263 | CREATE FUNCTION pg_promote(bool DEFAULT true) 264 | RETURNS void 265 | AS 'MODULE_PATHNAME' 266 | LANGUAGE C STRICT VOLATILE; 267 | REVOKE ALL ON FUNCTION pg_promote(bool) FROM PUBLIC; 268 | END IF; 269 | END; 270 | $$; 271 | 272 | CREATE FUNCTION pg_recovery_settings(OUT name text, OUT setting text) 273 | RETURNS SETOF record 274 | AS 'MODULE_PATHNAME' 275 | LANGUAGE C STRICT VOLATILE; 276 | REVOKE ALL ON FUNCTION pg_recovery_settings() FROM PUBLIC; 277 | 278 | CREATE FUNCTION pg_show_primary_conninfo() 279 | RETURNS text 280 | AS 'MODULE_PATHNAME' 281 | LANGUAGE C STRICT STABLE; 282 | REVOKE ALL ON FUNCTION pg_show_primary_conninfo() FROM PUBLIC; 283 | 284 | CREATE FUNCTION pg_postmaster_pid() 285 | RETURNS integer 286 | AS 'MODULE_PATHNAME' 287 | LANGUAGE C STRICT STABLE; 288 | 289 | CREATE FUNCTION pg_backend_start_time() 290 | RETURNS timestamptz 291 | AS 'MODULE_PATHNAME' 292 | LANGUAGE C STRICT STABLE; 293 | 294 | CREATE FUNCTION pg_list_relation_filepath(relation regclass) 295 | RETURNS SETOF text AS $$ 296 | DECLARE 297 | segcount bigint := 1; 298 | relationpath text; 299 | pathname text; 300 | BEGIN 301 | relationpath := pg_relation_filepath(relation); 302 | RETURN NEXT relationpath; 303 | IF current_setting('server_version_num')::integer < 90500 THEN 304 | RETURN; 305 | END IF; 306 | LOOP 307 | pathname := relationpath || '.' || segcount; 308 | EXIT WHEN pg_stat_file(pathname, true) IS NULL; 309 | RETURN NEXT pathname; 310 | segcount := segcount + 1; 311 | END LOOP; 312 | RETURN; 313 | END; 314 | $$ LANGUAGE plpgsql STRICT VOLATILE; 315 | 316 | CREATE FUNCTION pg_tablespace_version_directory() 317 | RETURNS text 318 | AS 'MODULE_PATHNAME' 319 | LANGUAGE C STRICT STABLE; 320 | REVOKE ALL ON FUNCTION pg_tablespace_version_directory() FROM PUBLIC; 321 | 322 | CREATE FUNCTION pg_file_write_binary(text, bytea) 323 | RETURNS bigint 324 | AS 'MODULE_PATHNAME' 325 | LANGUAGE C STRICT VOLATILE; 326 | REVOKE ALL ON FUNCTION pg_file_write_binary(text, bytea) FROM PUBLIC; 327 | 328 | /* pg_file_fsync function is available only in 9.4 or later */ 329 | DO $$ 330 | DECLARE 331 | pgversion INTEGER; 332 | BEGIN 333 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 334 | IF pgversion >= 90400 THEN 335 | CREATE FUNCTION pg_file_fsync(text) 336 | RETURNS void 337 | AS 'MODULE_PATHNAME' 338 | LANGUAGE C STRICT VOLATILE; 339 | REVOKE ALL ON FUNCTION pg_file_fsync(text) FROM PUBLIC; 340 | END IF; 341 | END; 342 | $$; 343 | 344 | CREATE FUNCTION to_octal(integer) 345 | RETURNS text 346 | AS 'MODULE_PATHNAME', 'to_octal32' 347 | LANGUAGE C STRICT IMMUTABLE; 348 | 349 | CREATE FUNCTION to_octal(bigint) 350 | RETURNS text 351 | AS 'MODULE_PATHNAME', 'to_octal64' 352 | LANGUAGE C STRICT IMMUTABLE; 353 | 354 | CREATE FUNCTION pg_text_to_hex(text) 355 | RETURNS text 356 | AS 'MODULE_PATHNAME' 357 | LANGUAGE C STRICT IMMUTABLE; 358 | 359 | CREATE FUNCTION pg_hex_to_text(text) 360 | RETURNS text 361 | AS 'MODULE_PATHNAME' 362 | LANGUAGE C STRICT IMMUTABLE; 363 | 364 | CREATE FUNCTION pg_chr(integer) 365 | RETURNS text 366 | AS 'MODULE_PATHNAME' 367 | LANGUAGE C STRICT IMMUTABLE; 368 | 369 | CREATE FUNCTION pg_utf8(integer) 370 | RETURNS text 371 | AS 'MODULE_PATHNAME', 'pg_chr' 372 | LANGUAGE C STRICT IMMUTABLE; 373 | 374 | CREATE FUNCTION pg_all_utf8(OUT code integer, OUT utf8 text) 375 | RETURNS SETOF record AS 376 | 'SELECT * FROM 377 | (SELECT code, pg_utf8(code) utf8 FROM generate_series(0, 1114111) code) tmp 378 | WHERE utf8 IS NOT NULL' 379 | LANGUAGE SQL IMMUTABLE; 380 | 381 | CREATE FUNCTION pg_eucjp(bit(8), bit(8) DEFAULT 'x00', bit(8) DEFAULT 'x00') 382 | RETURNS text 383 | AS 'MODULE_PATHNAME' 384 | LANGUAGE C STRICT IMMUTABLE; 385 | 386 | CREATE FUNCTION pg_all_eucjp(OUT code1 text, OUT code2 text, 387 | OUT code3 text, OUT eucjp text) RETURNS SETOF record AS $$ 388 | BEGIN 389 | RETURN QUERY 390 | SELECT CASE WHEN c1 <= 15 THEN 'x0' ELSE 'x' END || to_hex(c1), 391 | 'x00'::text, 'x00'::text, pg_eucjp(c1::bit(8)) 392 | FROM generate_series(0, 127) c1; 393 | RETURN QUERY SELECT 'x8e'::text, 'x' || to_hex(c2), 'x00'::text, 394 | pg_eucjp('x8e', c2::bit(8)) FROM generate_series(161, 223) c2; 395 | RETURN QUERY SELECT 'x' || to_hex(c1), 'x' || to_hex(c2), 'x00'::text, 396 | pg_eucjp(c1::bit(8), c2::bit(8)) 397 | FROM generate_series(161, 254) c1, generate_series(161, 254) c2; 398 | RETURN QUERY SELECT 'x8f'::text, 'x' || to_hex(c2), 'x' || to_hex(c3), 399 | pg_eucjp('x8f', c2::bit(8), c3::bit(8)) 400 | FROM generate_series(161, 254) c2, generate_series(161, 254) c3; 401 | END 402 | $$ LANGUAGE plpgsql IMMUTABLE; 403 | 404 | DO $$ 405 | DECLARE 406 | pgversion INTEGER; 407 | BEGIN 408 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 409 | IF pgversion >= 140000 THEN 410 | CREATE FUNCTION pg_euc_jp_to_utf8(integer, integer, cstring, internal, 411 | integer, bool DEFAULT false) 412 | RETURNS integer 413 | AS 'MODULE_PATHNAME' 414 | LANGUAGE C STRICT VOLATILE; 415 | ELSE 416 | CREATE FUNCTION pg_euc_jp_to_utf8(integer, integer, cstring, internal, integer) 417 | RETURNS void 418 | AS 'MODULE_PATHNAME' 419 | LANGUAGE C STRICT VOLATILE; 420 | END IF; 421 | END; 422 | $$; 423 | 424 | CREATE CONVERSION pg_euc_jp_to_utf8 425 | FOR 'EUC_JP' TO 'UTF8' FROM pg_euc_jp_to_utf8; 426 | 427 | /* PGLZ compression functions are available only in 9.5 or later */ 428 | DO $$ 429 | DECLARE 430 | pgversion INTEGER; 431 | BEGIN 432 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 433 | IF pgversion >= 90500 THEN 434 | CREATE FUNCTION pglz_compress(text) 435 | RETURNS bytea 436 | AS 'MODULE_PATHNAME', 'pglz_compress_text' 437 | LANGUAGE C STRICT IMMUTABLE; 438 | END IF; 439 | END; 440 | $$; 441 | 442 | DO $$ 443 | DECLARE 444 | pgversion INTEGER; 445 | BEGIN 446 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 447 | IF pgversion >= 90500 THEN 448 | CREATE FUNCTION pglz_compress_bytea(bytea) 449 | RETURNS bytea 450 | AS 'MODULE_PATHNAME', 'pglz_compress_bytea' 451 | LANGUAGE C STRICT IMMUTABLE; 452 | END IF; 453 | END; 454 | $$; 455 | 456 | DO $$ 457 | DECLARE 458 | pgversion INTEGER; 459 | BEGIN 460 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 461 | IF pgversion >= 90500 THEN 462 | CREATE FUNCTION pglz_decompress(bytea) 463 | RETURNS text 464 | AS 'MODULE_PATHNAME', 'pglz_decompress_text' 465 | LANGUAGE C STRICT IMMUTABLE; 466 | END IF; 467 | END; 468 | $$; 469 | 470 | DO $$ 471 | DECLARE 472 | pgversion INTEGER; 473 | BEGIN 474 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 475 | IF pgversion >= 90500 THEN 476 | CREATE FUNCTION pglz_decompress_bytea(bytea) 477 | RETURNS bytea 478 | AS 'MODULE_PATHNAME', 'pglz_decompress_bytea' 479 | LANGUAGE C STRICT IMMUTABLE; 480 | END IF; 481 | END; 482 | $$; 483 | 484 | DO $$ 485 | DECLARE 486 | pgversion INTEGER; 487 | BEGIN 488 | SELECT current_setting('server_version_num')::INTEGER INTO pgversion; 489 | IF pgversion >= 100000 THEN 490 | CREATE FUNCTION pg_saslprep(text) 491 | RETURNS text 492 | AS 'MODULE_PATHNAME', 'pg_cheat_saslprep' 493 | LANGUAGE C STRICT IMMUTABLE; 494 | END IF; 495 | END; 496 | $$; 497 | 498 | CREATE FUNCTION pg_advisory_xact_unlock(bigint) 499 | RETURNS boolean 500 | AS 'MODULE_PATHNAME', 'pg_advisory_xact_unlock_int8' 501 | LANGUAGE C STRICT IMMUTABLE; 502 | 503 | CREATE FUNCTION pg_advisory_xact_unlock_shared(bigint) 504 | RETURNS boolean 505 | AS 'MODULE_PATHNAME', 'pg_advisory_xact_unlock_shared_int8' 506 | LANGUAGE C STRICT IMMUTABLE; 507 | 508 | CREATE FUNCTION pg_advisory_xact_unlock(integer, integer) 509 | RETURNS boolean 510 | AS 'MODULE_PATHNAME', 'pg_advisory_xact_unlock_int4' 511 | LANGUAGE C STRICT IMMUTABLE; 512 | 513 | CREATE FUNCTION pg_advisory_xact_unlock_shared(integer, integer) 514 | RETURNS boolean 515 | AS 'MODULE_PATHNAME', 'pg_advisory_xact_unlock_shared_int4' 516 | LANGUAGE C STRICT IMMUTABLE; 517 | -------------------------------------------------------------------------------- /pg_cheat_funcs.c: -------------------------------------------------------------------------------- 1 | /*------------------------------------------------------------------------- 2 | * 3 | * pg_cheat_funcs.c 4 | * provides various cheat (but useful) functions 5 | * 6 | *------------------------------------------------------------------------- 7 | */ 8 | #include "postgres.h" 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #include "access/clog.h" 15 | #if PG_VERSION_NUM >= 90300 16 | #include "access/htup_details.h" 17 | #endif 18 | #include "access/subtrans.h" 19 | #include "access/xact.h" 20 | #include "access/xlog_internal.h" 21 | #if PG_VERSION_NUM >= 150000 22 | #include "access/xlogrecovery.h" 23 | #endif 24 | #include "access/transam.h" 25 | #include "catalog/catalog.h" 26 | #include "catalog/pg_type.h" 27 | #include "commands/prepare.h" 28 | #if PG_VERSION_NUM >= 90500 29 | #include "common/pg_lzcompress.h" 30 | #endif 31 | #if PG_VERSION_NUM >= 90300 32 | #include "common/relpath.h" 33 | #endif 34 | #if PG_VERSION_NUM >= 100000 35 | #include "common/saslprep.h" 36 | #endif 37 | #include "conv/euc_jp_to_utf8.extra" 38 | #if PG_VERSION_NUM >= 100000 39 | #include "conv/euc_jp_to_utf8.radix" 40 | #else 41 | #include "conv/euc_jp_to_utf8.map" 42 | #endif 43 | #include "funcapi.h" 44 | #include "libpq/auth.h" 45 | #include "libpq/libpq-be.h" 46 | #if PG_VERSION_NUM < 90300 47 | #include "libpq/pqsignal.h" 48 | #endif 49 | #include "mb/pg_wchar.h" 50 | #include "miscadmin.h" 51 | #include "postmaster/bgwriter.h" 52 | #include "replication/walreceiver.h" 53 | #include "replication/walsender.h" 54 | #if PG_VERSION_NUM >= 90200 55 | #include "replication/walsender_private.h" 56 | #endif 57 | #include "storage/fd.h" 58 | #include "storage/lwlock.h" 59 | #include "storage/proc.h" 60 | #include "storage/procarray.h" 61 | #include "utils/builtins.h" 62 | #if PG_VERSION_NUM >= 160000 63 | #include "utils/guc.h" 64 | #endif 65 | #include "utils/memutils.h" 66 | #include "utils/snapmgr.h" 67 | #if PG_VERSION_NUM >= 90400 68 | #include "utils/pg_lsn.h" 69 | #endif 70 | #include "utils/timestamp.h" 71 | #include "utils/plancache.h" 72 | #include "utils/varbit.h" 73 | #if PG_VERSION_NUM >= 130000 74 | #include "utils/xid8.h" 75 | #endif 76 | 77 | PG_MODULE_MAGIC; 78 | 79 | /* GUC variables */ 80 | static bool cheat_log_memory_context = false; 81 | static bool cheat_hide_appname = false; 82 | static char *cheat_hidden_appname = NULL; 83 | static bool cheat_log_session_start_options = false; 84 | static int cheat_scheduling_priority = 0; 85 | static bool cheat_exit_on_segv = false; 86 | 87 | /* Saved hook values in case of unload */ 88 | static ExecutorEnd_hook_type prev_ExecutorEnd = NULL; 89 | static ClientAuthentication_hook_type prev_ClientAuthentication = NULL; 90 | 91 | static int ExitOnSegvErrorLevel = FATAL; 92 | 93 | #if PG_VERSION_NUM >= 90500 94 | /* The information at the start of the compressed data */ 95 | typedef struct pglz_header 96 | { 97 | int32 vl_len_; /* varlena header (do not touch directly!) */ 98 | int32 rawsize; 99 | } pglz_header; 100 | 101 | #define PGLZ_HDRSZ ((int32) sizeof(pglz_header)) 102 | #define PGLZ_RAWSIZE(ptr) (((pglz_header *) (ptr))->rawsize & 0x3FFFFFFF) 103 | #define PGLZ_RAWDATA(ptr) (((char *) (ptr)) + PGLZ_HDRSZ) 104 | #define PGLZ_SET_RAWSIZE(ptr, len) \ 105 | (((pglz_header *) (ptr))->rawsize = ((len) & 0x3FFFFFFF)) 106 | #define PGLZ_SET_RAWSIZE_COMPRESSED(ptr, len) \ 107 | (((pglz_header *) (ptr))->rawsize = (((len) & 0x3FFFFFFF) | 0x40000000)) 108 | #define PGLZ_IS_COMPRESSED(ptr) \ 109 | ((((pglz_header *) (ptr))->rawsize & 0xC0000000) == 0x40000000) 110 | 111 | PG_FUNCTION_INFO_V1(pglz_compress_text); 112 | PG_FUNCTION_INFO_V1(pglz_compress_bytea); 113 | PG_FUNCTION_INFO_V1(pglz_decompress_text); 114 | PG_FUNCTION_INFO_V1(pglz_decompress_bytea); 115 | 116 | static struct varlena *PGLZCompress(struct varlena *source); 117 | static struct varlena *PGLZDecompress(struct varlena *source); 118 | #endif /* PG_VERSION_NUM >= 90500 */ 119 | 120 | /* 121 | * pg_stat_get_memory_context function is available only in 122 | * between 9.6 and 13. pg_stat_print_memory_context function 123 | * is available only in 13 or before. 124 | */ 125 | #if PG_VERSION_NUM < 140000 126 | #if PG_VERSION_NUM >= 90600 127 | PG_FUNCTION_INFO_V1(pg_stat_get_memory_context); 128 | #endif /* PG_VERSION_ NUM >= 90600 */ 129 | PG_FUNCTION_INFO_V1(pg_stat_print_memory_context); 130 | #endif /* PG_VERSION_NUM < 140000 */ 131 | 132 | #if PG_VERSION_NUM >= 90200 133 | PG_FUNCTION_INFO_V1(pg_cached_plan_source); 134 | #endif 135 | PG_FUNCTION_INFO_V1(pg_signal_process); 136 | PG_FUNCTION_INFO_V1(pg_get_priority); 137 | PG_FUNCTION_INFO_V1(pg_set_priority); 138 | PG_FUNCTION_INFO_V1(pg_segmentation_fault); 139 | PG_FUNCTION_INFO_V1(pg_process_config_file); 140 | #if PG_VERSION_NUM >= 90400 141 | PG_FUNCTION_INFO_V1(pg_xlogfile_name); 142 | #if PG_VERSION_NUM < 130000 143 | PG_FUNCTION_INFO_V1(pg_lsn_larger); 144 | PG_FUNCTION_INFO_V1(pg_lsn_smaller); 145 | #endif 146 | PG_FUNCTION_INFO_V1(pg_stat_get_syncrep_waiters); 147 | PG_FUNCTION_INFO_V1(pg_wait_syncrep); 148 | PG_FUNCTION_INFO_V1(pg_refresh_snapshot); 149 | #endif 150 | PG_FUNCTION_INFO_V1(pg_set_next_xid); 151 | PG_FUNCTION_INFO_V1(pg_xid_assignment); 152 | #if PG_VERSION_NUM >= 130000 153 | PG_FUNCTION_INFO_V1(pg_xid_to_xid8); 154 | #endif 155 | PG_FUNCTION_INFO_V1(pg_set_next_oid); 156 | PG_FUNCTION_INFO_V1(pg_oid_assignment); 157 | #if PG_VERSION_NUM < 160000 158 | PG_FUNCTION_INFO_V1(pg_advance_vacuum_cleanup_age); 159 | #endif 160 | PG_FUNCTION_INFO_V1(pg_checkpoint); 161 | #if PG_VERSION_NUM < 120000 162 | PG_FUNCTION_INFO_V1(pg_promote); 163 | #endif 164 | PG_FUNCTION_INFO_V1(pg_recovery_settings); 165 | PG_FUNCTION_INFO_V1(pg_show_primary_conninfo); 166 | PG_FUNCTION_INFO_V1(pg_postmaster_pid); 167 | PG_FUNCTION_INFO_V1(pg_backend_start_time); 168 | PG_FUNCTION_INFO_V1(pg_tablespace_version_directory); 169 | PG_FUNCTION_INFO_V1(pg_file_write_binary); 170 | #if PG_VERSION_NUM >= 90400 171 | PG_FUNCTION_INFO_V1(pg_file_fsync); 172 | #endif /* PG_VERSION_NUM >= 90400 */ 173 | PG_FUNCTION_INFO_V1(to_octal32); 174 | PG_FUNCTION_INFO_V1(to_octal64); 175 | PG_FUNCTION_INFO_V1(pg_text_to_hex); 176 | PG_FUNCTION_INFO_V1(pg_hex_to_text); 177 | PG_FUNCTION_INFO_V1(pg_chr); 178 | PG_FUNCTION_INFO_V1(pg_eucjp); 179 | PG_FUNCTION_INFO_V1(pg_euc_jp_to_utf8); 180 | #if PG_VERSION_NUM >= 100000 181 | PG_FUNCTION_INFO_V1(pg_cheat_saslprep); 182 | #endif 183 | PG_FUNCTION_INFO_V1(pg_advisory_xact_unlock_int8); 184 | PG_FUNCTION_INFO_V1(pg_advisory_xact_unlock_shared_int8); 185 | PG_FUNCTION_INFO_V1(pg_advisory_xact_unlock_int4); 186 | PG_FUNCTION_INFO_V1(pg_advisory_xact_unlock_shared_int4); 187 | 188 | /* 189 | * The function prototypes are created as a part of PG_FUNCTION_INFO_V1 190 | * macro since 9.4, and hence the declaration of the function prototypes 191 | * here is necessary only for 9.3 or before. 192 | */ 193 | #if PG_VERSION_NUM < 90400 194 | Datum pg_stat_print_memory_context(PG_FUNCTION_ARGS); 195 | #if PG_VERSION_NUM >= 90200 196 | Datum pg_cached_plan_source(PG_FUNCTION_ARGS); 197 | #endif 198 | Datum pg_signal_process(PG_FUNCTION_ARGS); 199 | Datum pg_get_priority(PG_FUNCTION_ARGS); 200 | Datum pg_set_priority(PG_FUNCTION_ARGS); 201 | Datum pg_segmentation_fault(PG_FUNCTION_ARGS); 202 | Datum pg_process_config_file(PG_FUNCTION_ARGS); 203 | Datum pg_set_next_xid(PG_FUNCTION_ARGS); 204 | Datum pg_xid_assignment(PG_FUNCTION_ARGS); 205 | Datum pg_set_next_oid(PG_FUNCTION_ARGS); 206 | Datum pg_oid_assignment(PG_FUNCTION_ARGS); 207 | #if PG_VERSION_NUM < 160000 208 | Datum pg_advance_vacuum_cleanup_age(PG_FUNCTION_ARGS); 209 | #endif 210 | Datum pg_checkpoint(PG_FUNCTION_ARGS); 211 | #if PG_VERSION_NUM < 120000 212 | Datum pg_promote(PG_FUNCTION_ARGS); 213 | #endif 214 | Datum pg_recovery_settings(PG_FUNCTION_ARGS); 215 | Datum pg_show_primary_conninfo(PG_FUNCTION_ARGS); 216 | Datum pg_postmaster_pid(PG_FUNCTION_ARGS); 217 | Datum pg_backend_start_time(PG_FUNCTION_ARGS); 218 | Datum pg_tablespace_version_directory(PG_FUNCTION_ARGS); 219 | Datum pg_file_write_binary(PG_FUNCTION_ARGS); 220 | Datum to_octal32(PG_FUNCTION_ARGS); 221 | Datum to_octal64(PG_FUNCTION_ARGS); 222 | Datum pg_text_to_hex(PG_FUNCTION_ARGS); 223 | Datum pg_hex_to_text(PG_FUNCTION_ARGS); 224 | Datum pg_chr(PG_FUNCTION_ARGS); 225 | Datum pg_eucjp(PG_FUNCTION_ARGS); 226 | Datum pg_euc_jp_to_utf8(PG_FUNCTION_ARGS); 227 | Datum pg_advisory_xact_unlock_int8(PG_FUNCTION_ARGS); 228 | Datum pg_advisory_xact_unlock_shared_int8(PG_FUNCTION_ARGS); 229 | Datum pg_advisory_xact_unlock_int4(PG_FUNCTION_ARGS); 230 | Datum pg_advisory_xact_unlock_shared_int4(PG_FUNCTION_ARGS); 231 | #endif 232 | 233 | void _PG_init(void); 234 | void _PG_fini(void); 235 | 236 | static void CheatExecutorEnd(QueryDesc *queryDesc); 237 | static void CheatClientAuthentication(Port *port, int status); 238 | 239 | #if PG_VERSION_NUM < 140000 240 | #if PG_VERSION_NUM >= 90600 241 | static void PutMemoryContextStatsTupleStore(Tuplestorestate *tupstore, 242 | TupleDesc tupdesc, MemoryContext context, 243 | MemoryContext parent, int level); 244 | #endif /* PG_VERSION_NUM >= 90600 */ 245 | static void PrintMemoryContextStats(MemoryContext context, int level); 246 | #endif /* PG_VERSION_NUM < 140000 */ 247 | 248 | static int GetSignalByName(char *signame); 249 | static ReturnSetInfo *InitReturnSetFunc(FunctionCallInfo fcinfo); 250 | #if PG_VERSION_NUM >= 90400 251 | static const char *SyncRepGetWaitModeString(int mode); 252 | #endif 253 | static int GetProcessPriority(int pid, int elevel); 254 | static void SetProcessPriority(int pid, int priority, int elevel); 255 | static void ExitOnSegvHandler(SIGNAL_ARGS); 256 | static void CheckPostgresPid(int pid); 257 | static bool IsWalSenderPid(int pid); 258 | static bool IsWalReceiverPid(int pid); 259 | #if PG_VERSION_NUM < 120000 260 | static void CreateEmptyFile(const char *filepath); 261 | #endif 262 | static text *Bits8GetText(bits8 b1, bits8 b2, bits8 c3, int len); 263 | 264 | static void assign_scheduling_priority(int newval, void *extra); 265 | static const char *show_scheduling_priority(void); 266 | static void assign_exit_on_segv(bool newval, void *extra); 267 | 268 | /* 269 | * Module load callback 270 | */ 271 | void 272 | _PG_init(void) 273 | { 274 | /* Define custom GUC variables. */ 275 | DefineCustomBoolVariable("pg_cheat_funcs.log_memory_context", 276 | "Cause statistics about all memory contexts to be logged.", 277 | NULL, 278 | &cheat_log_memory_context, 279 | false, 280 | PGC_SUSET, 281 | 0, 282 | NULL, 283 | NULL, 284 | NULL); 285 | 286 | DefineCustomBoolVariable("pg_cheat_funcs.hide_appname", 287 | "Hide client's application_name from view.", 288 | NULL, 289 | &cheat_hide_appname, 290 | false, 291 | PGC_SIGHUP, 292 | 0, 293 | NULL, 294 | NULL, 295 | NULL); 296 | 297 | DefineCustomStringVariable("pg_cheat_funcs.hidden_appname", 298 | "Hidden client's application_name.", 299 | NULL, 300 | &cheat_hidden_appname, 301 | "", 302 | PGC_USERSET, 303 | 0, 304 | NULL, 305 | NULL, 306 | NULL); 307 | 308 | DefineCustomBoolVariable("pg_cheat_funcs.log_session_start_options", 309 | "Log options sent to the server at connection start.", 310 | NULL, 311 | &cheat_log_session_start_options, 312 | false, 313 | #if PG_VERSION_NUM >= 90500 314 | PGC_SU_BACKEND, 315 | #else 316 | PGC_BACKEND, 317 | #endif 318 | 0, 319 | NULL, 320 | NULL, 321 | NULL); 322 | 323 | DefineCustomIntVariable("pg_cheat_funcs.scheduling_priority", 324 | "Set the scheduling priority of PostgreSQL server process.", 325 | NULL, 326 | &cheat_scheduling_priority, 327 | 0, 328 | -20, 329 | 19, 330 | PGC_USERSET, 331 | 0, 332 | NULL, 333 | assign_scheduling_priority, 334 | show_scheduling_priority); 335 | 336 | DefineCustomBoolVariable("pg_cheat_funcs.exit_on_segv", 337 | "Terminate session on segmentation fault.", 338 | NULL, 339 | &cheat_exit_on_segv, 340 | false, 341 | PGC_USERSET, 342 | 0, 343 | NULL, 344 | assign_exit_on_segv, 345 | NULL); 346 | 347 | EmitWarningsOnPlaceholders("pg_cheat_funcs"); 348 | 349 | /* Install hooks. */ 350 | prev_ExecutorEnd = ExecutorEnd_hook; 351 | ExecutorEnd_hook = CheatExecutorEnd; 352 | prev_ClientAuthentication = ClientAuthentication_hook; 353 | ClientAuthentication_hook = CheatClientAuthentication; 354 | } 355 | 356 | /* 357 | * Module unload callback 358 | */ 359 | void 360 | _PG_fini(void) 361 | { 362 | /* Uninstall hooks. */ 363 | ExecutorEnd_hook = prev_ExecutorEnd; 364 | ClientAuthentication_hook = prev_ClientAuthentication; 365 | } 366 | 367 | /* 368 | * ExecutorEnd hook 369 | */ 370 | static void 371 | CheatExecutorEnd(QueryDesc *queryDesc) 372 | { 373 | if (prev_ExecutorEnd) 374 | prev_ExecutorEnd(queryDesc); 375 | else 376 | standard_ExecutorEnd(queryDesc); 377 | 378 | /* Print statistics about TopMemoryContext and all its descendants */ 379 | if (cheat_log_memory_context) 380 | #if PG_VERSION_NUM >= 140000 381 | HandleLogMemoryContextInterrupt(); 382 | #else 383 | PrintMemoryContextStats(TopMemoryContext, 0); 384 | #endif 385 | } 386 | 387 | #if PG_VERSION_NUM >= 130000 388 | #define CHEAT_LNEXT(l, c) lnext(l, c) 389 | #else 390 | #define CHEAT_LNEXT(l, c) lnext(c) 391 | #endif 392 | 393 | /* 394 | * ClientAuthentication hook 395 | */ 396 | static void 397 | CheatClientAuthentication(Port *port, int status) 398 | { 399 | if (prev_ClientAuthentication) 400 | prev_ClientAuthentication(port, status); 401 | 402 | /* Hide client's application_name from view */ 403 | if (cheat_hide_appname) 404 | { 405 | List *gucopts = port->guc_options; 406 | ListCell *cell; 407 | ListCell *next; 408 | 409 | for (cell = list_head(gucopts); cell != NULL; cell = next) 410 | { 411 | char *name = lfirst(cell); 412 | char *value; 413 | 414 | next = CHEAT_LNEXT(port->guc_options, cell); 415 | 416 | if (strcmp(name, "application_name") != 0) 417 | { 418 | next = CHEAT_LNEXT(port->guc_options, next); 419 | continue; 420 | } 421 | 422 | cell = next; 423 | next = CHEAT_LNEXT(port->guc_options, next); 424 | value = lfirst(cell); 425 | SetConfigOption("pg_cheat_funcs.hidden_appname", value, 426 | PGC_USERSET, PGC_S_CLIENT); 427 | strcpy(value, ""); /* reset application_name to an empty */ 428 | } 429 | } 430 | 431 | /* Log options sent to the server at connection start */ 432 | if (cheat_log_session_start_options) 433 | { 434 | ListCell *cell = list_head(port->guc_options); 435 | 436 | while (cell) 437 | { 438 | char *name; 439 | char *value; 440 | 441 | name = lfirst(cell); 442 | cell = CHEAT_LNEXT(port->guc_options, cell); 443 | 444 | value = lfirst(cell); 445 | cell = CHEAT_LNEXT(port->guc_options, cell); 446 | 447 | ereport(LOG, 448 | (errmsg("session-start options: %s = %s", name, value))); 449 | } 450 | } 451 | } 452 | 453 | /* 454 | * Initialize function returning a tuplestore (multiple rows). 455 | */ 456 | static ReturnSetInfo * 457 | InitReturnSetFunc(FunctionCallInfo fcinfo) 458 | { 459 | ReturnSetInfo *rsinfo = (ReturnSetInfo *) fcinfo->resultinfo; 460 | TupleDesc tupdesc; 461 | Tuplestorestate *tupstore; 462 | MemoryContext per_query_ctx; 463 | MemoryContext oldcontext; 464 | 465 | /* check to see if caller supports us returning a tuplestore */ 466 | if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) 467 | ereport(ERROR, 468 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), 469 | errmsg("set-valued function called in context that cannot accept a set"))); 470 | if (!(rsinfo->allowedModes & SFRM_Materialize)) 471 | ereport(ERROR, 472 | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), 473 | errmsg("materialize mode required, but it is not " \ 474 | "allowed in this context"))); 475 | 476 | /* Build a tuple descriptor for our result type */ 477 | if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) 478 | elog(ERROR, "return type must be a row type"); 479 | 480 | per_query_ctx = rsinfo->econtext->ecxt_per_query_memory; 481 | oldcontext = MemoryContextSwitchTo(per_query_ctx); 482 | 483 | tupstore = tuplestore_begin_heap(true, false, work_mem); 484 | rsinfo->returnMode = SFRM_Materialize; 485 | rsinfo->setResult = tupstore; 486 | rsinfo->setDesc = tupdesc; 487 | 488 | MemoryContextSwitchTo(oldcontext); 489 | 490 | return rsinfo; 491 | } 492 | 493 | #if PG_VERSION_NUM < 140000 494 | #if PG_VERSION_NUM >= 90600 495 | /* 496 | * Return statistics about all memory contexts. 497 | */ 498 | Datum 499 | pg_stat_get_memory_context(PG_FUNCTION_ARGS) 500 | { 501 | ReturnSetInfo *rsinfo; 502 | TupleDesc tupdesc; 503 | Tuplestorestate *tupstore; 504 | 505 | rsinfo = InitReturnSetFunc(fcinfo); 506 | tupdesc = rsinfo->setDesc; 507 | tupstore = rsinfo->setResult; 508 | 509 | PutMemoryContextStatsTupleStore(tupstore, tupdesc, 510 | TopMemoryContext, NULL, 0); 511 | 512 | return (Datum) 0; 513 | } 514 | 515 | static void 516 | PutMemoryContextStatsTupleStore(Tuplestorestate *tupstore, 517 | TupleDesc tupdesc, MemoryContext context, 518 | MemoryContext parent, int level) 519 | { 520 | #define PG_STAT_GET_MEMORY_CONTEXT_COLS 8 521 | Datum values[PG_STAT_GET_MEMORY_CONTEXT_COLS]; 522 | bool nulls[PG_STAT_GET_MEMORY_CONTEXT_COLS]; 523 | MemoryContextCounters stat; 524 | MemoryContext child; 525 | 526 | if (context == NULL) 527 | return; 528 | 529 | /* Examine the context itself */ 530 | memset(&stat, 0, sizeof(stat)); 531 | #if PG_VERSION_NUM >= 110000 532 | (*context->methods->stats) (context, NULL, (void *) &level, &stat); 533 | #else 534 | (*context->methods->stats) (context, level, false, &stat); 535 | #endif 536 | 537 | memset(nulls, 0, sizeof(nulls)); 538 | values[0] = CStringGetTextDatum(context->name); 539 | if (parent == NULL) 540 | nulls[1] = true; 541 | else 542 | values[1] = CStringGetTextDatum(parent->name); 543 | values[2] = Int32GetDatum(level); 544 | values[3] = Int64GetDatum(stat.totalspace); 545 | values[4] = Int64GetDatum(stat.nblocks); 546 | values[5] = Int64GetDatum(stat.freespace); 547 | values[6] = Int64GetDatum(stat.freechunks); 548 | values[7] = Int64GetDatum(stat.totalspace - stat.freespace); 549 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 550 | 551 | for (child = context->firstchild; child != NULL; child = child->nextchild) 552 | { 553 | PutMemoryContextStatsTupleStore(tupstore, tupdesc, 554 | child, context, level + 1); 555 | } 556 | } 557 | #endif /* PG_VERSION_NUM >= 90600 */ 558 | 559 | /* 560 | * Print statistics about TopMemoryContext and all its descendants. 561 | */ 562 | Datum 563 | pg_stat_print_memory_context(PG_FUNCTION_ARGS) 564 | { 565 | PrintMemoryContextStats(TopMemoryContext, 0); 566 | 567 | PG_RETURN_VOID(); 568 | } 569 | 570 | #if PG_VERSION_NUM >= 110000 571 | /* 572 | * Simple version of MemoryContextStatsPrint() added in PostgreSQL 11. 573 | */ 574 | static void 575 | SimpleMemoryContextStatsPrint(MemoryContext context, void *passthru, 576 | const char *stats_string) 577 | { 578 | int level = *(int *) passthru; 579 | const char *name = context->name; 580 | int i; 581 | 582 | for (i = 0; i < level; i++) 583 | fprintf(stderr, " "); 584 | fprintf(stderr, "%s: %s\n", name, stats_string); 585 | } 586 | #endif /* PG_VERSION_NUM >= 110000 */ 587 | 588 | /* 589 | * Print statistics about the named context and all its descendants. 590 | */ 591 | static void 592 | PrintMemoryContextStats(MemoryContext context, int level) 593 | { 594 | MemoryContext child; 595 | 596 | if (context == NULL) 597 | return; 598 | 599 | #if PG_VERSION_NUM >= 110000 600 | (*context->methods->stats) (context, SimpleMemoryContextStatsPrint, 601 | (void *) &level, NULL); 602 | #elif PG_VERSION_NUM >= 90600 603 | (*context->methods->stats) (context, level, true, NULL); 604 | #else 605 | (*context->methods->stats) (context, level); 606 | #endif 607 | 608 | for (child = context->firstchild; child != NULL; child = child->nextchild) 609 | PrintMemoryContextStats(child, level + 1); 610 | } 611 | #endif /* PG_VERSION_NUM < 140000 */ 612 | 613 | #if PG_VERSION_NUM >= 90200 614 | /* 615 | * Return information about the cached plan of the specified 616 | * prepared statement. 617 | */ 618 | Datum 619 | pg_cached_plan_source(PG_FUNCTION_ARGS) 620 | { 621 | char *stmt_name = text_to_cstring(PG_GETARG_TEXT_P(0)); 622 | TupleDesc tupdesc; 623 | Datum values[5]; 624 | bool nulls[5]; 625 | PreparedStatement *stmt; 626 | CachedPlanSource *plansource; 627 | 628 | /* Look it up in the hash table */ 629 | stmt = FetchPreparedStatement(stmt_name, true); 630 | plansource = stmt->plansource; 631 | 632 | /* Initialize values and NULL flags arrays */ 633 | MemSet(values, 0, sizeof(values)); 634 | MemSet(nulls, 0, sizeof(nulls)); 635 | 636 | /* Initialize attributes information in the tuple descriptor */ 637 | #if PG_VERSION_NUM >= 120000 638 | tupdesc = CreateTemplateTupleDesc(5); 639 | #else 640 | tupdesc = CreateTemplateTupleDesc(5, false); 641 | #endif 642 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "generic_cost", 643 | FLOAT8OID, -1, 0); 644 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "total_custom_cost", 645 | FLOAT8OID, -1, 0); 646 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "num_custom_plans", 647 | INT4OID, -1, 0); 648 | TupleDescInitEntry(tupdesc, (AttrNumber) 4, "force_generic", 649 | BOOLOID, -1, 0); 650 | TupleDescInitEntry(tupdesc, (AttrNumber) 5, "force_custom", 651 | BOOLOID, -1, 0); 652 | 653 | BlessTupleDesc(tupdesc); 654 | 655 | /* Fill values and NULLs */ 656 | values[0] = Float8GetDatum(plansource->generic_cost); 657 | values[1] = Float8GetDatum(plansource->total_custom_cost); 658 | values[2] = Int32GetDatum(plansource->num_custom_plans); 659 | if (plansource->cursor_options & CURSOR_OPT_GENERIC_PLAN) 660 | values[3] = true; 661 | if (plansource->cursor_options & CURSOR_OPT_CUSTOM_PLAN) 662 | values[4] = true; 663 | 664 | /* Returns the record as Datum */ 665 | PG_RETURN_DATUM(HeapTupleGetDatum( 666 | heap_form_tuple(tupdesc, values, nulls))); 667 | } 668 | #endif /* PG_VERSION_NUM >= 90200 */ 669 | 670 | /* 671 | * Send a signal to PostgreSQL server process. 672 | */ 673 | Datum 674 | pg_signal_process(PG_FUNCTION_ARGS) 675 | { 676 | int pid = PG_GETARG_INT32(0); 677 | char *signame = text_to_cstring(PG_GETARG_TEXT_P(1)); 678 | int sig = GetSignalByName(signame); 679 | 680 | CheckPostgresPid(pid); 681 | if (kill(pid, sig)) 682 | ereport(ERROR, 683 | (errmsg("could not send signal to process %d: %m", pid))); 684 | 685 | PG_RETURN_VOID(); 686 | } 687 | 688 | /* 689 | * Check to see if a given pid is a running postmaster, backend, walsender 690 | * or walreceiver. 691 | */ 692 | static void 693 | CheckPostgresPid(int pid) 694 | { 695 | if (PostmasterPid != pid && !IsBackendPid(pid) && 696 | !IsWalSenderPid(pid) && !IsWalReceiverPid(pid)) 697 | ereport(ERROR, 698 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 699 | (errmsg("PID %d is not a PostgreSQL server process", pid)))); 700 | } 701 | 702 | /* 703 | * Get the scheduling priority of PostgreSQL server process. 704 | */ 705 | Datum 706 | pg_get_priority(PG_FUNCTION_ARGS) 707 | { 708 | int pid = PG_GETARG_INT32(0); 709 | int priority; 710 | 711 | CheckPostgresPid(pid); 712 | priority = GetProcessPriority(pid, ERROR); 713 | PG_RETURN_INT32(priority); 714 | } 715 | 716 | /* 717 | * Get the scheduling priority of the specified process. 718 | */ 719 | static int 720 | GetProcessPriority(int pid, int elevel) 721 | { 722 | int priority = 0; 723 | int save_errno = errno; 724 | 725 | errno = 0; 726 | priority = getpriority(PRIO_PROCESS, pid); 727 | if (errno != 0) 728 | ereport(elevel, 729 | (errmsg("could not get the scheduling priority of process %d: %m", pid))); 730 | errno = save_errno; 731 | 732 | return priority; 733 | } 734 | 735 | /* 736 | * Set the scheduling priority of PostgreSQL server process. 737 | */ 738 | Datum 739 | pg_set_priority(PG_FUNCTION_ARGS) 740 | { 741 | int pid = PG_GETARG_INT32(0); 742 | int priority = PG_GETARG_INT32(1); 743 | 744 | CheckPostgresPid(pid); 745 | SetProcessPriority(pid, priority, ERROR); 746 | PG_RETURN_VOID(); 747 | } 748 | 749 | /* 750 | * Set the scheduling priority of the specified process. 751 | */ 752 | static void 753 | SetProcessPriority(int pid, int priority, int elevel) 754 | { 755 | int save_errno = errno; 756 | 757 | if (setpriority(PRIO_PROCESS, pid, priority) != 0) 758 | ereport(elevel, 759 | (errmsg("could not set the scheduling priority of process %d to %d: %m", pid, priority))); 760 | errno = save_errno; 761 | } 762 | 763 | static void 764 | assign_scheduling_priority(int newval, void *extra) 765 | { 766 | /* See comments in assign_tcp_keepalives_idle in PostgreSQL source */ 767 | SetProcessPriority(getpid(), newval, WARNING); 768 | } 769 | 770 | static const char * 771 | show_scheduling_priority(void) 772 | { 773 | /* See comments in assign_tcp_keepalives_idle in PostgreSQL source */ 774 | static char nbuf[16]; 775 | 776 | snprintf(nbuf, sizeof(nbuf), "%d", GetProcessPriority(getpid(), WARNING)); 777 | return nbuf; 778 | } 779 | 780 | /* 781 | * Cause segmentation fault. 782 | * 783 | * If treat_fatal_as_error is true, make the SEGV handler report ERROR 784 | * instead of FATAL. This is intended for testing. 785 | */ 786 | Datum 787 | pg_segmentation_fault(PG_FUNCTION_ARGS) 788 | { 789 | bool treat_fatal_as_error = PG_GETARG_BOOL(0); 790 | int *ptr = NULL; 791 | 792 | if (treat_fatal_as_error) 793 | ExitOnSegvErrorLevel = ERROR; 794 | 795 | PG_TRY(); 796 | { 797 | *ptr = 10; 798 | } 799 | PG_CATCH(); 800 | { 801 | ExitOnSegvErrorLevel = FATAL; 802 | PG_RE_THROW(); 803 | } 804 | PG_END_TRY(); 805 | 806 | PG_RETURN_VOID(); 807 | } 808 | 809 | static void 810 | ExitOnSegvHandler(SIGNAL_ARGS) 811 | { 812 | ereport(ExitOnSegvErrorLevel, 813 | (errcode(ERRCODE_INTERNAL_ERROR), 814 | errmsg("terminating PostgreSQL server process due to segmentation fault"))); 815 | } 816 | 817 | static void 818 | assign_exit_on_segv(bool newval, void *extra) 819 | { 820 | if (newval) 821 | pqsignal(SIGSEGV, ExitOnSegvHandler); 822 | else 823 | pqsignal(SIGSEGV, SIG_DFL); 824 | } 825 | 826 | /* 827 | * Return signal corresponding to the given signal name. 828 | */ 829 | static int 830 | GetSignalByName(char *signame) 831 | { 832 | if (strcmp(signame, "HUP") == 0) 833 | return SIGHUP; 834 | else if (strcmp(signame, "INT") == 0) 835 | return SIGINT; 836 | else if (strcmp(signame, "QUIT") == 0) 837 | return SIGQUIT; 838 | else if (strcmp(signame, "ABRT") == 0) 839 | return SIGABRT; 840 | else if (strcmp(signame, "KILL") == 0) 841 | return SIGKILL; 842 | else if (strcmp(signame, "TERM") == 0) 843 | return SIGTERM; 844 | else if (strcmp(signame, "USR1") == 0) 845 | return SIGUSR1; 846 | else if (strcmp(signame, "USR2") == 0) 847 | return SIGUSR2; 848 | else if (strcmp(signame, "CONT") == 0) 849 | return SIGCONT; 850 | else if (strcmp(signame, "STOP") == 0) 851 | return SIGSTOP; 852 | else 853 | ereport(ERROR, 854 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 855 | (errmsg("unrecognized signal name \"%s\"", signame), 856 | errhint("Valid signal names are \"HUP\", \"INT\", \"QUIT\", \"ABRT\", \"KILL\", \"TERM\", \"USR1\", \"USR2\", \"CONT\", and \"STOP\".")))); 857 | 858 | return 0; /* keep compiler quiet */ 859 | } 860 | 861 | /* 862 | * Is a given pid a running walsender? 863 | */ 864 | static bool 865 | IsWalSenderPid(int pid) 866 | { 867 | int i; 868 | 869 | if (pid == 0) 870 | return false; 871 | 872 | for (i = 0; i < max_wal_senders; i++) 873 | { 874 | WalSnd *walsnd = &WalSndCtl->walsnds[i]; 875 | 876 | if (walsnd->pid == pid) 877 | return true; 878 | } 879 | 880 | return false; 881 | } 882 | 883 | /* 884 | * Is a given pid a running walreceiver? 885 | */ 886 | static bool 887 | IsWalReceiverPid(int pid) 888 | { 889 | WalRcvData *walrcv = WalRcv; 890 | 891 | if (pid == 0) 892 | return false; 893 | 894 | return (walrcv->pid == pid); 895 | } 896 | 897 | /* 898 | * Read and process the configuration file. 899 | */ 900 | Datum 901 | pg_process_config_file(PG_FUNCTION_ARGS) 902 | { 903 | ProcessConfigFile(PGC_SIGHUP); 904 | PG_RETURN_VOID(); 905 | } 906 | 907 | #if PG_VERSION_NUM >= 90400 908 | /* 909 | * Compute an xlog file name given a WAL location. 910 | */ 911 | Datum 912 | pg_xlogfile_name(PG_FUNCTION_ARGS) 913 | { 914 | XLogSegNo xlogsegno; 915 | XLogRecPtr locationpoint = PG_GETARG_LSN(0); 916 | char xlogfilename[MAXFNAMELEN]; 917 | bool recovery = PG_GETARG_BOOL(1); 918 | #if PG_VERSION_NUM >= 150000 919 | TimeLineID ThisTimeLineID = 0; 920 | #endif 921 | 922 | if (!recovery && RecoveryInProgress()) 923 | ereport(ERROR, 924 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), 925 | errmsg("recovery is in progress"), 926 | errhint("pg_xlogfile_name() cannot be executed during recovery."))); 927 | 928 | #if PG_VERSION_NUM >= 150000 929 | /* Use the currently-replaying timeline while in recovery */ 930 | if (RecoveryInProgress()) 931 | (void) GetXLogReplayRecPtr(&ThisTimeLineID); 932 | else 933 | ThisTimeLineID = GetWALInsertionTimeLine(); 934 | #endif 935 | 936 | #if PG_VERSION_NUM >= 110000 937 | XLByteToPrevSeg(locationpoint, xlogsegno, wal_segment_size); 938 | XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno, wal_segment_size); 939 | #else 940 | XLByteToPrevSeg(locationpoint, xlogsegno); 941 | XLogFileName(xlogfilename, ThisTimeLineID, xlogsegno); 942 | #endif 943 | 944 | PG_RETURN_TEXT_P(cstring_to_text(xlogfilename)); 945 | } 946 | 947 | /* 948 | * Create min() and max() aggregates for pg_lsn only in 12 or before. 949 | * They are supported in core since 13. 950 | */ 951 | #if PG_VERSION_NUM < 130000 952 | /* 953 | * Return larger pg_lsn value. 954 | */ 955 | Datum 956 | pg_lsn_larger(PG_FUNCTION_ARGS) 957 | { 958 | XLogRecPtr lsn1 = PG_GETARG_LSN(0); 959 | XLogRecPtr lsn2 = PG_GETARG_LSN(1); 960 | XLogRecPtr result; 961 | 962 | result = ((lsn1 > lsn2) ? lsn1 : lsn2); 963 | 964 | PG_RETURN_LSN(result); 965 | } 966 | 967 | /* 968 | * Return smaller pg_lsn value. 969 | */ 970 | Datum 971 | pg_lsn_smaller(PG_FUNCTION_ARGS) 972 | { 973 | XLogRecPtr lsn1 = PG_GETARG_LSN(0); 974 | XLogRecPtr lsn2 = PG_GETARG_LSN(1); 975 | XLogRecPtr result; 976 | 977 | result = ((lsn1 < lsn2) ? lsn1 : lsn2); 978 | 979 | PG_RETURN_LSN(result); 980 | } 981 | #endif /* PG_VERSION_NUM < 130000 */ 982 | 983 | /* 984 | * Return statistics about all syncrep waiters. 985 | */ 986 | Datum 987 | pg_stat_get_syncrep_waiters(PG_FUNCTION_ARGS) 988 | { 989 | #define PG_STAT_GET_SYNCREP_WAITERS_COLS 3 990 | ReturnSetInfo *rsinfo; 991 | TupleDesc tupdesc; 992 | Tuplestorestate *tupstore; 993 | int i; 994 | 995 | rsinfo = InitReturnSetFunc(fcinfo); 996 | tupdesc = rsinfo->setDesc; 997 | tupstore = rsinfo->setResult; 998 | 999 | LWLockAcquire(SyncRepLock, LW_SHARED); 1000 | for (i = 0; i < NUM_SYNC_REP_WAIT_MODE; i++) 1001 | { 1002 | #if PG_VERSION_NUM >= 160000 1003 | dlist_iter iter; 1004 | 1005 | dlist_foreach(iter, &WalSndCtl->SyncRepQueue[i]) 1006 | { 1007 | PGPROC *proc = dlist_container(PGPROC, syncRepLinks, iter.cur); 1008 | #else 1009 | PGPROC *proc = NULL; 1010 | 1011 | proc = (PGPROC *) SHMQueueNext(&(WalSndCtl->SyncRepQueue[i]), 1012 | &(WalSndCtl->SyncRepQueue[i]), 1013 | offsetof(PGPROC, syncRepLinks)); 1014 | while (proc) 1015 | { 1016 | #endif 1017 | Datum values[PG_STAT_GET_SYNCREP_WAITERS_COLS]; 1018 | bool nulls[PG_STAT_GET_SYNCREP_WAITERS_COLS]; 1019 | 1020 | memset(nulls, 0, sizeof(nulls)); 1021 | values[0] = Int32GetDatum(proc->pid); 1022 | values[1] = LSNGetDatum(proc->waitLSN); 1023 | values[2] = CStringGetTextDatum(SyncRepGetWaitModeString(i)); 1024 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 1025 | 1026 | #if PG_VERSION_NUM < 160000 1027 | proc = (PGPROC *) SHMQueueNext(&(WalSndCtl->SyncRepQueue[i]), 1028 | &(proc->syncRepLinks), 1029 | offsetof(PGPROC, syncRepLinks)); 1030 | #endif 1031 | } 1032 | } 1033 | LWLockRelease(SyncRepLock); 1034 | 1035 | return (Datum) 0; 1036 | } 1037 | 1038 | /* 1039 | * Return a string constant representing the SyncRepWaitMode. 1040 | */ 1041 | static const char * 1042 | SyncRepGetWaitModeString(int mode) 1043 | { 1044 | switch (mode) 1045 | { 1046 | case SYNC_REP_NO_WAIT: 1047 | return "no wait"; 1048 | case SYNC_REP_WAIT_WRITE: 1049 | return "write"; 1050 | case SYNC_REP_WAIT_FLUSH: 1051 | return "flush"; 1052 | #if PG_VERSION_NUM >= 90600 1053 | case SYNC_REP_WAIT_APPLY: 1054 | return "apply"; 1055 | #endif 1056 | } 1057 | return "unknown"; 1058 | } 1059 | 1060 | /* 1061 | * Wait for synchronous replication. 1062 | */ 1063 | Datum 1064 | pg_wait_syncrep(PG_FUNCTION_ARGS) 1065 | { 1066 | XLogRecPtr recptr = PG_GETARG_LSN(0); 1067 | 1068 | #if PG_VERSION_NUM >= 90600 1069 | SyncRepWaitForLSN(recptr, true); 1070 | #else 1071 | SyncRepWaitForLSN(recptr); 1072 | #endif 1073 | 1074 | PG_RETURN_VOID(); 1075 | } 1076 | 1077 | /* 1078 | * Forcibly refresh the current snapshot. 1079 | */ 1080 | Datum 1081 | pg_refresh_snapshot(PG_FUNCTION_ARGS) 1082 | { 1083 | int save_XactIsoLevel; 1084 | bool XactIsoLevelNeedsReset = false; 1085 | 1086 | if (FirstSnapshotSet && IsolationUsesXactSnapshot()) 1087 | { 1088 | save_XactIsoLevel = XactIsoLevel; 1089 | XactIsoLevel = XACT_READ_COMMITTED; 1090 | XactIsoLevelNeedsReset = true; 1091 | } 1092 | 1093 | GetTransactionSnapshot(); 1094 | 1095 | if (XactIsoLevelNeedsReset) 1096 | XactIsoLevel = save_XactIsoLevel; 1097 | 1098 | PG_RETURN_VOID(); 1099 | } 1100 | #endif /* PG_VERSION_NUM >= 90400 */ 1101 | 1102 | /* 1103 | * ShmemVariableCache was renamed to TransamVariables in v17 1104 | * (commit b31ba5310b). 1105 | */ 1106 | #if PG_VERSION_NUM >= 170000 1107 | #define ShmemVariableCache TransamVariables 1108 | #endif /* PG_VERSION_NUM >= 170000 */ 1109 | 1110 | /* 1111 | * Set and return the next transaction ID. 1112 | */ 1113 | Datum 1114 | pg_set_next_xid(PG_FUNCTION_ARGS) 1115 | { 1116 | TransactionId xid = PG_GETARG_UINT32(0); 1117 | #if PG_VERSION_NUM >= 120000 1118 | uint32 epoch; 1119 | #endif 1120 | 1121 | if (RecoveryInProgress()) 1122 | ereport(ERROR, 1123 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), 1124 | errmsg("recovery is in progress"), 1125 | errhint("pg_set_next_xid() cannot be executed during recovery."))); 1126 | 1127 | LWLockAcquire(XidGenLock, LW_EXCLUSIVE); 1128 | #if PG_VERSION_NUM >= 140000 1129 | epoch = EpochFromFullTransactionId(ShmemVariableCache->nextXid); 1130 | ShmemVariableCache->nextXid 1131 | = FullTransactionIdFromEpochAndXid(epoch, xid); 1132 | #elif PG_VERSION_NUM >= 120000 1133 | epoch = EpochFromFullTransactionId(ShmemVariableCache->nextFullXid); 1134 | ShmemVariableCache->nextFullXid 1135 | = FullTransactionIdFromEpochAndXid(epoch, xid); 1136 | #else 1137 | ShmemVariableCache->nextXid = xid; 1138 | #endif 1139 | LWLockRelease(XidGenLock); 1140 | 1141 | /* 1142 | * Make sure that CLOG has room for the given next XID. These macros are 1143 | * borrowed from src/backend/access/transam/clog.c. 1144 | */ 1145 | #define CLOG_XACTS_PER_BYTE 4 1146 | #define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE) 1147 | #define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE) 1148 | if (TransactionIdToPgIndex(xid) != 0 && 1149 | !TransactionIdEquals(xid, FirstNormalTransactionId)) 1150 | ExtendCLOG(xid - TransactionIdToPgIndex(xid)); 1151 | 1152 | /* 1153 | * Make sure that SUBTRANS has room for the given next XID. These macros 1154 | * are borrowed from src/backend/access/transam/subtrans.c. 1155 | */ 1156 | #define SUBTRANS_XACTS_PER_PAGE (BLCKSZ / sizeof(TransactionId)) 1157 | #define TransactionIdToEntry(xid) ((xid) % (TransactionId) SUBTRANS_XACTS_PER_PAGE) 1158 | if (TransactionIdToEntry(xid) != 0 && 1159 | !TransactionIdEquals(xid, FirstNormalTransactionId)) 1160 | ExtendSUBTRANS(xid - TransactionIdToEntry(xid)); 1161 | 1162 | PG_RETURN_UINT32(xid); 1163 | } 1164 | 1165 | /* 1166 | * Return information about XID assignment state. 1167 | */ 1168 | Datum 1169 | pg_xid_assignment(PG_FUNCTION_ARGS) 1170 | { 1171 | #define PG_XID_ASSIGNMENT_COLS 7 1172 | TupleDesc tupdesc; 1173 | Datum values[PG_XID_ASSIGNMENT_COLS]; 1174 | bool nulls[PG_XID_ASSIGNMENT_COLS]; 1175 | TransactionId nextXid; 1176 | TransactionId oldestXid; 1177 | TransactionId xidVacLimit; 1178 | TransactionId xidWarnLimit; 1179 | TransactionId xidStopLimit; 1180 | TransactionId xidWrapLimit; 1181 | Oid oldestXidDB; 1182 | #if PG_VERSION_NUM >= 120000 1183 | FullTransactionId full_xid; 1184 | #endif 1185 | 1186 | /* Initialise values and NULL flags arrays */ 1187 | MemSet(values, 0, sizeof(values)); 1188 | MemSet(nulls, 0, sizeof(nulls)); 1189 | 1190 | /* Initialise attributes information in the tuple descriptor */ 1191 | #if PG_VERSION_NUM >= 120000 1192 | tupdesc = CreateTemplateTupleDesc(PG_XID_ASSIGNMENT_COLS); 1193 | #else 1194 | tupdesc = CreateTemplateTupleDesc(PG_XID_ASSIGNMENT_COLS, false); 1195 | #endif 1196 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "next_xid", 1197 | XIDOID, -1, 0); 1198 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "oldest_xid", 1199 | XIDOID, -1, 0); 1200 | TupleDescInitEntry(tupdesc, (AttrNumber) 3, "xid_vac_limit", 1201 | XIDOID, -1, 0); 1202 | TupleDescInitEntry(tupdesc, (AttrNumber) 4, "xid_warn_limit", 1203 | XIDOID, -1, 0); 1204 | TupleDescInitEntry(tupdesc, (AttrNumber) 5, "xid_stop_limit", 1205 | XIDOID, -1, 0); 1206 | TupleDescInitEntry(tupdesc, (AttrNumber) 6, "xid_wrap_limit", 1207 | XIDOID, -1, 0); 1208 | TupleDescInitEntry(tupdesc, (AttrNumber) 7, "oldest_xid_db", 1209 | OIDOID, -1, 0); 1210 | 1211 | BlessTupleDesc(tupdesc); 1212 | 1213 | /* Take a lock to ensure value consistency */ 1214 | LWLockAcquire(XidGenLock, LW_SHARED); 1215 | #if PG_VERSION_NUM >= 140000 1216 | full_xid = ShmemVariableCache->nextXid; 1217 | nextXid = XidFromFullTransactionId(full_xid); 1218 | #elif PG_VERSION_NUM >= 120000 1219 | full_xid = ShmemVariableCache->nextFullXid; 1220 | nextXid = XidFromFullTransactionId(full_xid); 1221 | #else 1222 | nextXid = ShmemVariableCache->nextXid; 1223 | #endif 1224 | oldestXid = ShmemVariableCache->oldestXid; 1225 | xidVacLimit = ShmemVariableCache->xidVacLimit; 1226 | xidWarnLimit = ShmemVariableCache->xidWarnLimit; 1227 | xidStopLimit = ShmemVariableCache->xidStopLimit; 1228 | xidWrapLimit = ShmemVariableCache->xidWrapLimit; 1229 | oldestXidDB = ShmemVariableCache->oldestXidDB; 1230 | LWLockRelease(XidGenLock); 1231 | 1232 | /* Fetch values */ 1233 | values[0] = TransactionIdGetDatum(nextXid); 1234 | values[1] = TransactionIdGetDatum(oldestXid); 1235 | values[2] = TransactionIdGetDatum(xidVacLimit); 1236 | values[3] = TransactionIdGetDatum(xidWarnLimit); 1237 | values[4] = TransactionIdGetDatum(xidStopLimit); 1238 | values[5] = TransactionIdGetDatum(xidWrapLimit); 1239 | values[6] = ObjectIdGetDatum(oldestXidDB); 1240 | 1241 | /* Returns the record as Datum */ 1242 | PG_RETURN_DATUM(HeapTupleGetDatum( 1243 | heap_form_tuple(tupdesc, values, nulls))); 1244 | } 1245 | 1246 | #if PG_VERSION_NUM >= 130000 1247 | /* 1248 | * This is copy-pasted from widen_snapshot_xid in PostgreSQL source. 1249 | */ 1250 | static FullTransactionId 1251 | widen_snapshot_xid(TransactionId xid, FullTransactionId next_fxid) 1252 | { 1253 | TransactionId next_xid = XidFromFullTransactionId(next_fxid); 1254 | uint32 epoch = EpochFromFullTransactionId(next_fxid); 1255 | 1256 | if (!TransactionIdIsNormal(xid)) 1257 | return FullTransactionIdFromEpochAndXid(0, xid); 1258 | 1259 | if (xid > next_xid) 1260 | epoch--; 1261 | 1262 | return FullTransactionIdFromEpochAndXid(epoch, xid); 1263 | } 1264 | 1265 | /* 1266 | * Convert the specified TransactionId (with 32-bit type xid) to 1267 | * FullTransactionId (with 64-bit type xid8). 1268 | */ 1269 | Datum 1270 | pg_xid_to_xid8(PG_FUNCTION_ARGS) 1271 | { 1272 | #if PG_VERSION_NUM >= 140000 1273 | TransactionId xid = PG_GETARG_TRANSACTIONID(0); 1274 | #else 1275 | TransactionId xid = PG_GETARG_UINT32(0); 1276 | #endif 1277 | FullTransactionId fxid; 1278 | 1279 | fxid = widen_snapshot_xid(xid, ReadNextFullTransactionId()); 1280 | PG_RETURN_FULLTRANSACTIONID(fxid); 1281 | } 1282 | #endif /* PG_VERSION_NUM >= 130000 */ 1283 | 1284 | /* 1285 | * Set and return the next object ID. 1286 | */ 1287 | Datum 1288 | pg_set_next_oid(PG_FUNCTION_ARGS) 1289 | { 1290 | Oid oid = PG_GETARG_OID(0); 1291 | Oid result; 1292 | 1293 | if (RecoveryInProgress()) 1294 | ereport(ERROR, 1295 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), 1296 | errmsg("recovery is in progress"), 1297 | errhint("pg_set_next_oid() cannot be executed during recovery."))); 1298 | 1299 | #define VAR_OID_PREFETCH 8192 1300 | LWLockAcquire(OidGenLock, LW_EXCLUSIVE); 1301 | ShmemVariableCache->nextOid = 1302 | (oid < ((Oid) FirstNormalObjectId)) ? FirstNormalObjectId : oid; 1303 | XLogPutNextOid(ShmemVariableCache->nextOid + VAR_OID_PREFETCH); 1304 | ShmemVariableCache->oidCount = VAR_OID_PREFETCH; 1305 | result = ShmemVariableCache->nextOid; 1306 | LWLockRelease(OidGenLock); 1307 | 1308 | PG_RETURN_OID(result); 1309 | } 1310 | 1311 | /* 1312 | * Return information about OID assignment state. 1313 | */ 1314 | Datum 1315 | pg_oid_assignment(PG_FUNCTION_ARGS) 1316 | { 1317 | #define PG_OID_ASSIGNMENT_COLS 2 1318 | TupleDesc tupdesc; 1319 | Datum values[PG_OID_ASSIGNMENT_COLS]; 1320 | bool nulls[PG_OID_ASSIGNMENT_COLS]; 1321 | Oid nextOid; 1322 | uint32 oidCount; 1323 | 1324 | /* Initialise values and NULL flags arrays */ 1325 | MemSet(values, 0, sizeof(values)); 1326 | MemSet(nulls, 0, sizeof(nulls)); 1327 | 1328 | /* Initialise attributes information in the tuple descriptor */ 1329 | #if PG_VERSION_NUM >= 120000 1330 | tupdesc = CreateTemplateTupleDesc(PG_OID_ASSIGNMENT_COLS); 1331 | #else 1332 | tupdesc = CreateTemplateTupleDesc(PG_OID_ASSIGNMENT_COLS, false); 1333 | #endif 1334 | TupleDescInitEntry(tupdesc, (AttrNumber) 1, "next_oid", 1335 | OIDOID, -1, 0); 1336 | TupleDescInitEntry(tupdesc, (AttrNumber) 2, "oid_count", 1337 | INT4OID, -1, 0); 1338 | 1339 | BlessTupleDesc(tupdesc); 1340 | 1341 | /* Take a lock to ensure value consistency */ 1342 | LWLockAcquire(OidGenLock, LW_SHARED); 1343 | nextOid = ShmemVariableCache->nextOid; 1344 | oidCount = ShmemVariableCache->oidCount; 1345 | LWLockRelease(OidGenLock); 1346 | 1347 | /* Fetch values */ 1348 | values[0] = ObjectIdGetDatum(nextOid); 1349 | values[1] = UInt32GetDatum(oidCount); 1350 | 1351 | /* Returns the record as Datum */ 1352 | PG_RETURN_DATUM(HeapTupleGetDatum( 1353 | heap_form_tuple(tupdesc, values, nulls))); 1354 | } 1355 | 1356 | #if PG_VERSION_NUM < 160000 1357 | /* 1358 | * Specify the number of transactions by which VACUUM and HOT updates 1359 | * will advance cleanup of dead row versions. 1360 | */ 1361 | Datum 1362 | pg_advance_vacuum_cleanup_age(PG_FUNCTION_ARGS) 1363 | { 1364 | static bool advanced = false; 1365 | static int save_cleanup_age = 0; 1366 | static int orig_cleanup_age = 0; 1367 | 1368 | if (!advanced || vacuum_defer_cleanup_age != save_cleanup_age) 1369 | orig_cleanup_age = vacuum_defer_cleanup_age; 1370 | 1371 | if (PG_ARGISNULL(0)) 1372 | { 1373 | vacuum_defer_cleanup_age = orig_cleanup_age; 1374 | advanced = false; 1375 | } 1376 | else 1377 | { 1378 | vacuum_defer_cleanup_age = -PG_GETARG_INT32(0); 1379 | advanced = true; 1380 | } 1381 | save_cleanup_age = vacuum_defer_cleanup_age; 1382 | 1383 | PG_RETURN_INT32(-vacuum_defer_cleanup_age); 1384 | } 1385 | #endif /* PG_VERSION_NUM < 160000 */ 1386 | 1387 | /* 1388 | * Perform a checkpoint. 1389 | */ 1390 | Datum 1391 | pg_checkpoint(PG_FUNCTION_ARGS) 1392 | { 1393 | bool fast = PG_GETARG_BOOL(0); 1394 | bool wait = PG_GETARG_BOOL(1); 1395 | bool force = PG_GETARG_BOOL(2); 1396 | 1397 | RequestCheckpoint((fast ? CHECKPOINT_IMMEDIATE : 0) | 1398 | (wait ? CHECKPOINT_WAIT : 0) | 1399 | (force ? CHECKPOINT_FORCE : 0)); 1400 | 1401 | PG_RETURN_VOID(); 1402 | } 1403 | 1404 | /* 1405 | * Create pg_promote() only in 11 or before. 1406 | * It's supported in core since 12. 1407 | */ 1408 | #if PG_VERSION_NUM < 120000 1409 | /* 1410 | * Promote the standby server. 1411 | */ 1412 | Datum 1413 | pg_promote(PG_FUNCTION_ARGS) 1414 | { 1415 | #if PG_VERSION_NUM >= 90300 1416 | bool fast = PG_GETARG_BOOL(0); 1417 | #endif 1418 | 1419 | #define PROMOTE_SIGNAL_FILE "promote" 1420 | #define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote" 1421 | 1422 | if (!RecoveryInProgress()) 1423 | ereport(ERROR, 1424 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), 1425 | errmsg("server is not in standby mode"))); 1426 | 1427 | #if PG_VERSION_NUM >= 90300 1428 | CreateEmptyFile(fast ? PROMOTE_SIGNAL_FILE : 1429 | FALLBACK_PROMOTE_SIGNAL_FILE); 1430 | #else 1431 | CreateEmptyFile(PROMOTE_SIGNAL_FILE); 1432 | #endif 1433 | 1434 | if (kill(PostmasterPid, SIGUSR1)) 1435 | ereport(ERROR, 1436 | (errmsg("could not send signal to postmaster: %m"))); 1437 | 1438 | PG_RETURN_VOID(); 1439 | } 1440 | 1441 | /* 1442 | * Create empty file. 1443 | */ 1444 | static void 1445 | CreateEmptyFile(const char *filepath) 1446 | { 1447 | FILE *fd; 1448 | 1449 | if ((fd = AllocateFile(filepath, "w")) == NULL) 1450 | ereport(ERROR, 1451 | (errcode_for_file_access(), 1452 | errmsg("could not create file \"%s\": %m", filepath))); 1453 | 1454 | if (FreeFile(fd)) 1455 | ereport(ERROR, 1456 | (errcode_for_file_access(), 1457 | errmsg("could not write file \"%s\": %m", filepath))); 1458 | } 1459 | #endif /* PG_VERSION_NUM < 120000 */ 1460 | 1461 | /* 1462 | * Return a table of all parameter settings in recovery.conf. 1463 | */ 1464 | Datum 1465 | pg_recovery_settings(PG_FUNCTION_ARGS) 1466 | { 1467 | #define PG_RECOVERY_SETTINGS_COLS 2 1468 | #define RECOVERY_COMMAND_FILE "recovery.conf" 1469 | ReturnSetInfo *rsinfo; 1470 | TupleDesc tupdesc; 1471 | Tuplestorestate *tupstore; 1472 | FILE *fd; 1473 | ConfigVariable *item, 1474 | *head = NULL, 1475 | *tail = NULL; 1476 | 1477 | rsinfo = InitReturnSetFunc(fcinfo); 1478 | tupdesc = rsinfo->setDesc; 1479 | tupstore = rsinfo->setResult; 1480 | 1481 | fd = AllocateFile(RECOVERY_COMMAND_FILE, "r"); 1482 | if (fd == NULL) 1483 | { 1484 | if (errno != ENOENT) 1485 | ereport(ERROR, 1486 | (errcode_for_file_access(), 1487 | errmsg("could not open recovery command file \"%s\": %m", 1488 | RECOVERY_COMMAND_FILE))); 1489 | } 1490 | else 1491 | { 1492 | (void) ParseConfigFp(fd, RECOVERY_COMMAND_FILE, 0, ERROR, &head, &tail); 1493 | FreeFile(fd); 1494 | } 1495 | 1496 | for (item = head; item; item = item->next) 1497 | { 1498 | Datum values[PG_RECOVERY_SETTINGS_COLS]; 1499 | bool nulls[PG_RECOVERY_SETTINGS_COLS]; 1500 | 1501 | memset(nulls, 0, sizeof(nulls)); 1502 | values[0] = CStringGetTextDatum(item->name); 1503 | values[1] = CStringGetTextDatum(item->value); 1504 | tuplestore_putvalues(tupstore, tupdesc, values, nulls); 1505 | } 1506 | 1507 | return (Datum) 0; 1508 | } 1509 | 1510 | /* 1511 | * Return the connection string that walreceiver uses to connect with 1512 | * the primary. 1513 | */ 1514 | Datum 1515 | pg_show_primary_conninfo(PG_FUNCTION_ARGS) 1516 | { 1517 | char conninfo[MAXCONNINFO]; 1518 | WalRcvData *walrcv = WalRcv; 1519 | 1520 | SpinLockAcquire(&walrcv->mutex); 1521 | strlcpy(conninfo, (char *) walrcv->conninfo, MAXCONNINFO); 1522 | SpinLockRelease(&walrcv->mutex); 1523 | 1524 | if (conninfo[0] == '\0') 1525 | PG_RETURN_NULL(); 1526 | PG_RETURN_TEXT_P(cstring_to_text(conninfo)); 1527 | } 1528 | 1529 | /* 1530 | * Return the PID of the postmaster process. 1531 | */ 1532 | Datum 1533 | pg_postmaster_pid(PG_FUNCTION_ARGS) 1534 | { 1535 | PG_RETURN_INT32(PostmasterPid); 1536 | } 1537 | 1538 | /* 1539 | * Return the time when this backend process was started. 1540 | */ 1541 | Datum 1542 | pg_backend_start_time(PG_FUNCTION_ARGS) 1543 | { 1544 | if (MyProcPort) 1545 | #if PG_VERSION_NUM >= 120000 1546 | PG_RETURN_TIMESTAMPTZ(MyStartTimestamp); 1547 | #else 1548 | PG_RETURN_TIMESTAMPTZ(MyProcPort->SessionStartTime); 1549 | #endif 1550 | else 1551 | PG_RETURN_NULL(); 1552 | } 1553 | 1554 | /* 1555 | * Return the name of major-version-specific tablespace subdirectory 1556 | */ 1557 | Datum 1558 | pg_tablespace_version_directory(PG_FUNCTION_ARGS) 1559 | { 1560 | PG_RETURN_TEXT_P(cstring_to_text(TABLESPACE_VERSION_DIRECTORY)); 1561 | } 1562 | 1563 | /* 1564 | * Write bytea data to the file. 1565 | */ 1566 | Datum 1567 | pg_file_write_binary(PG_FUNCTION_ARGS) 1568 | { 1569 | FILE *f; 1570 | char *filename; 1571 | bytea *data; 1572 | int64 count = 0; 1573 | 1574 | filename = text_to_cstring(PG_GETARG_TEXT_P(0)); 1575 | canonicalize_path(filename); 1576 | data = PG_GETARG_BYTEA_P(1); 1577 | 1578 | if (!(f = fopen(filename, "wb"))) 1579 | ereport(ERROR, 1580 | (errcode_for_file_access(), 1581 | errmsg("could not open file \"%s\" for writing: %m", 1582 | filename))); 1583 | 1584 | if (VARSIZE(data) != 0) 1585 | { 1586 | count = fwrite(VARDATA(data), 1, VARSIZE(data) - VARHDRSZ, f); 1587 | 1588 | if (count != VARSIZE(data) - VARHDRSZ) 1589 | ereport(ERROR, 1590 | (errcode_for_file_access(), 1591 | errmsg("could not write file \"%s\": %m", filename))); 1592 | } 1593 | fclose(f); 1594 | 1595 | PG_RETURN_INT64(count); 1596 | } 1597 | 1598 | #if PG_VERSION_NUM >= 90400 1599 | /* 1600 | * Fsync a file or directory. 1601 | */ 1602 | Datum 1603 | pg_file_fsync(PG_FUNCTION_ARGS) 1604 | { 1605 | char *filename; 1606 | struct stat statbuf; 1607 | 1608 | filename = text_to_cstring(PG_GETARG_TEXT_P(0)); 1609 | canonicalize_path(filename); 1610 | 1611 | if (stat(filename, &statbuf) < 0) 1612 | ereport(ERROR, 1613 | (errcode_for_file_access(), 1614 | errmsg("could not stat file \"%s\": %m", filename))); 1615 | 1616 | fsync_fname(filename, S_ISDIR(statbuf.st_mode)); 1617 | 1618 | PG_RETURN_VOID(); 1619 | } 1620 | #endif /* PG_VERSION_NUM >= 90400 */ 1621 | 1622 | #define OCTALBASE 8 1623 | /* 1624 | * Convert an int32 to a string containing a base 8 (octal) representation of 1625 | * the number. 1626 | */ 1627 | Datum 1628 | to_octal32(PG_FUNCTION_ARGS) 1629 | { 1630 | uint32 value = (uint32) PG_GETARG_INT32(0); 1631 | char *ptr; 1632 | const char *digits = "012345678"; 1633 | char buf[32]; /* bigger than needed, but reasonable */ 1634 | 1635 | ptr = buf + sizeof(buf) - 1; 1636 | *ptr = '\0'; 1637 | 1638 | do 1639 | { 1640 | *--ptr = digits[value % OCTALBASE]; 1641 | value /= OCTALBASE; 1642 | } while (ptr > buf && value); 1643 | 1644 | PG_RETURN_TEXT_P(cstring_to_text(ptr)); 1645 | } 1646 | 1647 | /* 1648 | * Convert an int64 to a string containing a base 8 (octal) representation of 1649 | * the number. 1650 | */ 1651 | Datum 1652 | to_octal64(PG_FUNCTION_ARGS) 1653 | { 1654 | uint64 value = (uint64) PG_GETARG_INT64(0); 1655 | char *ptr; 1656 | const char *digits = "012345678"; 1657 | char buf[32]; /* bigger than needed, but reasonable */ 1658 | 1659 | ptr = buf + sizeof(buf) - 1; 1660 | *ptr = '\0'; 1661 | 1662 | do 1663 | { 1664 | *--ptr = digits[value % OCTALBASE]; 1665 | value /= OCTALBASE; 1666 | } while (ptr > buf && value); 1667 | 1668 | PG_RETURN_TEXT_P(cstring_to_text(ptr)); 1669 | } 1670 | 1671 | /* 1672 | * Convert text to its equivalent hexadecimal representation. 1673 | */ 1674 | Datum 1675 | pg_text_to_hex(PG_FUNCTION_ARGS) 1676 | { 1677 | text *s = PG_GETARG_TEXT_P(0); 1678 | uint8 *sp = (uint8 *) VARDATA(s); 1679 | int len = VARSIZE(s) - VARHDRSZ; 1680 | int i; 1681 | char *result; 1682 | char *r; 1683 | 1684 | #define HEXDIG(z) ((z)<10 ? ((z)+'0') : ((z)-10+'a')) 1685 | 1686 | result = (char *) palloc(len * 2 + 1); 1687 | r = result; 1688 | for (i = 0; i < len; i++, sp++) 1689 | { 1690 | *r++ = HEXDIG((*sp) >> 4); 1691 | *r++ = HEXDIG((*sp) & 0xF); 1692 | } 1693 | *r = '\0'; 1694 | 1695 | PG_RETURN_TEXT_P(cstring_to_text(result)); 1696 | } 1697 | 1698 | /* 1699 | * Convert hexadecimal representation to its equivalent text. 1700 | */ 1701 | Datum 1702 | pg_hex_to_text(PG_FUNCTION_ARGS) 1703 | { 1704 | text *s = PG_GETARG_TEXT_P(0); 1705 | uint8 *sp = (uint8 *) VARDATA(s); 1706 | int len = VARSIZE(s) - VARHDRSZ; 1707 | int i; 1708 | int bc; 1709 | char *result; 1710 | char *r; 1711 | uint8 x; 1712 | 1713 | result = (char *) palloc0(len / 2 + 1 + 1); 1714 | r = result; 1715 | for (bc = 0, i = 0; i < len; i++, sp++) 1716 | { 1717 | if (*sp >= '0' && *sp <= '9') 1718 | x = (uint8) (*sp - '0'); 1719 | else if (*sp >= 'A' && *sp <= 'F') 1720 | x = (uint8) (*sp - 'A') + 10; 1721 | else if (*sp >= 'a' && *sp <= 'f') 1722 | x = (uint8) (*sp - 'a') + 10; 1723 | else 1724 | ereport(ERROR, 1725 | (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), 1726 | errmsg("\"%c\" is not a valid hexadecimal digit", 1727 | *sp))); 1728 | if (bc) 1729 | { 1730 | *r++ |= x; 1731 | bc = 0; 1732 | } 1733 | else 1734 | { 1735 | *r = x << 4; 1736 | bc = 1; 1737 | } 1738 | } 1739 | 1740 | PG_RETURN_TEXT_P(cstring_to_text(result)); 1741 | } 1742 | 1743 | /* 1744 | * Return the character with the given code. 1745 | */ 1746 | Datum 1747 | pg_chr(PG_FUNCTION_ARGS) 1748 | { 1749 | Datum res; 1750 | 1751 | PG_TRY(); 1752 | { 1753 | res = chr (fcinfo); 1754 | } 1755 | PG_CATCH(); 1756 | { 1757 | FlushErrorState(); 1758 | PG_RETURN_NULL(); 1759 | } 1760 | PG_END_TRY(); 1761 | 1762 | PG_RETURN_DATUM(res); 1763 | } 1764 | 1765 | /* 1766 | * Return text representation for three bits8. 1767 | */ 1768 | static text * 1769 | Bits8GetText(bits8 b1, bits8 b2, bits8 b3, int len) 1770 | { 1771 | text *result; 1772 | bits8 *tmp; 1773 | 1774 | result = (text *) palloc(VARHDRSZ + len); 1775 | SET_VARSIZE(result, VARHDRSZ + len); 1776 | tmp = (bits8 *) VARDATA(result); 1777 | 1778 | tmp[0] = b1; 1779 | if (len > 1) 1780 | tmp[1] = b2; 1781 | if (len > 2) 1782 | tmp[2] = b3; 1783 | 1784 | return result; 1785 | } 1786 | 1787 | /* 1788 | * Return EUC-JP character with the given codes. 1789 | */ 1790 | Datum 1791 | pg_eucjp(PG_FUNCTION_ARGS) 1792 | { 1793 | bits8 b1 = *(VARBITS(PG_GETARG_VARBIT_P(0))); 1794 | bits8 b2 = *(VARBITS(PG_GETARG_VARBIT_P(1))); 1795 | bits8 b3 = *(VARBITS(PG_GETARG_VARBIT_P(2))); 1796 | int len; 1797 | 1798 | if (GetDatabaseEncoding() != PG_EUC_JP) 1799 | ereport(ERROR, 1800 | (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), 1801 | errmsg("database encoding is %s", GetDatabaseEncodingName()), 1802 | errhint("pg_eucjp() can be executed only under EUC_JP encoding."))); 1803 | 1804 | #define IS_EUC_RANGE_VALID(b) ((b) >= 0xa1 && (b) <= 0xfe) 1805 | 1806 | switch (b1) 1807 | { 1808 | case SS2: /* JIS X 0201 */ 1809 | if (b2 < 0xa1 || b2 > 0xdf || b3 != 0x00) 1810 | PG_RETURN_NULL(); 1811 | len = 2; 1812 | break; 1813 | 1814 | case SS3: /* JIS X 0212 */ 1815 | if (!IS_EUC_RANGE_VALID(b2) || !IS_EUC_RANGE_VALID(b3)) 1816 | PG_RETURN_NULL(); 1817 | len = 3; 1818 | break; 1819 | 1820 | default: 1821 | if (IS_HIGHBIT_SET(b1)) /* JIS X 0208? */ 1822 | { 1823 | if (!IS_EUC_RANGE_VALID(b1) || !IS_EUC_RANGE_VALID(b2) || 1824 | b3 != 0x00) 1825 | PG_RETURN_NULL(); 1826 | len = 2; 1827 | } 1828 | else /* must be ASCII */ 1829 | { 1830 | if (b2 != 0x00 || b3 != 0x00) 1831 | PG_RETURN_NULL(); 1832 | len = 1; 1833 | } 1834 | break; 1835 | } 1836 | 1837 | PG_RETURN_TEXT_P(Bits8GetText(b1, b2, b3, len)); 1838 | } 1839 | 1840 | #if PG_VERSION_NUM >= 90500 1841 | /* 1842 | * Comparison routine to bsearch() for local code -> UTF-8. 1843 | */ 1844 | static int 1845 | compare_local_to_utf(const void *p1, const void *p2) 1846 | { 1847 | uint32 v1, 1848 | v2; 1849 | 1850 | v1 = *(const uint32 *) p1; 1851 | v2 = ((const pg_local_to_utf *) p2)->code; 1852 | return (v1 > v2) ? 1 : ((v1 == v2) ? 0 : -1); 1853 | } 1854 | 1855 | /* 1856 | * Perform extra mapping of EUC_JP ranges to UTF-8. 1857 | */ 1858 | static uint32 1859 | extra_euc_jp_to_utf8(uint32 code) 1860 | { 1861 | const pg_local_to_utf *p; 1862 | 1863 | p = bsearch(&code, ExtraLUmapEUC_JP, lengthof(ExtraLUmapEUC_JP), 1864 | sizeof(pg_local_to_utf), compare_local_to_utf); 1865 | return p ? p->utf : 0; 1866 | } 1867 | #endif /* PG_VERSION_NUM >= 90500 */ 1868 | 1869 | /* 1870 | * Convert string from EUC_JP to UTF-8. 1871 | */ 1872 | Datum 1873 | pg_euc_jp_to_utf8(PG_FUNCTION_ARGS) 1874 | { 1875 | unsigned char *src = (unsigned char *) PG_GETARG_CSTRING(2); 1876 | unsigned char *dest = (unsigned char *) PG_GETARG_CSTRING(3); 1877 | int len = PG_GETARG_INT32(4); 1878 | #if PG_VERSION_NUM >= 140000 1879 | bool noError = PG_GETARG_BOOL(5); 1880 | #endif 1881 | 1882 | #if PG_VERSION_NUM < 90500 1883 | static pg_local_to_utf_combined cmap[lengthof(ExtraLUmapEUC_JP)]; 1884 | static bool first_time = true; 1885 | #endif 1886 | 1887 | CHECK_ENCODING_CONVERSION_ARGS(PG_EUC_JP, PG_UTF8); 1888 | 1889 | #if PG_VERSION_NUM >= 140000 1890 | LocalToUtf(src, len, dest, 1891 | &euc_jp_to_unicode_tree, 1892 | NULL, 0, 1893 | extra_euc_jp_to_utf8, 1894 | PG_EUC_JP, noError); 1895 | #elif PG_VERSION_NUM >= 100000 1896 | LocalToUtf(src, len, dest, 1897 | &euc_jp_to_unicode_tree, 1898 | NULL, 0, 1899 | extra_euc_jp_to_utf8, 1900 | PG_EUC_JP); 1901 | #elif PG_VERSION_NUM >= 90500 1902 | LocalToUtf(src, len, dest, 1903 | LUmapEUC_JP, lengthof(LUmapEUC_JP), 1904 | NULL, 0, 1905 | extra_euc_jp_to_utf8, 1906 | PG_EUC_JP); 1907 | #else 1908 | 1909 | /* 1910 | * The first time through, we create the extra conversion map in 1911 | * pg_local_to_utf_combined struct so that LocalToUtf() can use it as 1912 | * "secondary" conversion map which is consulted after no match is found 1913 | * in ordinary map. 1914 | */ 1915 | if (first_time) 1916 | { 1917 | int i; 1918 | const pg_local_to_utf *p = ExtraLUmapEUC_JP; 1919 | pg_local_to_utf_combined *cp = cmap; 1920 | 1921 | for (i = 0; i < lengthof(ExtraLUmapEUC_JP); i++) 1922 | { 1923 | cp->code = p->code; 1924 | cp->utf1 = p->utf; 1925 | cp->utf2 = 0; 1926 | p++; 1927 | cp++; 1928 | } 1929 | first_time = false; 1930 | } 1931 | 1932 | LocalToUtf(src, dest, 1933 | LUmapEUC_JP, cmap, 1934 | lengthof(LUmapEUC_JP), 1935 | lengthof(ExtraLUmapEUC_JP), 1936 | PG_EUC_JP, len); 1937 | #endif 1938 | 1939 | PG_RETURN_VOID(); 1940 | } 1941 | 1942 | #if PG_VERSION_NUM >= 90500 1943 | /* 1944 | * Create a compressed version of a text datum 1945 | */ 1946 | Datum 1947 | pglz_compress_text(PG_FUNCTION_ARGS) 1948 | { 1949 | text *source = PG_GETARG_TEXT_P(0); 1950 | 1951 | PG_RETURN_BYTEA_P(PGLZCompress((struct varlena *) source)); 1952 | } 1953 | 1954 | /* 1955 | * Create a compressed version of a bytea datum 1956 | */ 1957 | Datum 1958 | pglz_compress_bytea(PG_FUNCTION_ARGS) 1959 | { 1960 | bytea *source = PG_GETARG_BYTEA_P(0); 1961 | 1962 | PG_RETURN_BYTEA_P(PGLZCompress((struct varlena *) source)); 1963 | } 1964 | 1965 | /* 1966 | * Create a compressed version of a varlena datum 1967 | */ 1968 | static struct varlena * 1969 | PGLZCompress(struct varlena *source) 1970 | { 1971 | struct varlena *dest; 1972 | int32 orig_len = VARSIZE(source) - VARHDRSZ; 1973 | int32 len; 1974 | 1975 | dest = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(orig_len) + PGLZ_HDRSZ); 1976 | 1977 | /* 1978 | * We recheck the actual size even if pglz_compress() reports success, 1979 | * because it might be satisfied with having saved as little as one byte 1980 | * in the compressed data. 1981 | */ 1982 | len = pglz_compress(VARDATA(source), orig_len, 1983 | PGLZ_RAWDATA(dest), PGLZ_strategy_default); 1984 | if (len >= 0 && len < orig_len) 1985 | { 1986 | /* successful compression */ 1987 | PGLZ_SET_RAWSIZE_COMPRESSED(dest, orig_len); 1988 | SET_VARSIZE(dest, len + PGLZ_HDRSZ); 1989 | } 1990 | else 1991 | { 1992 | /* incompressible data */ 1993 | PGLZ_SET_RAWSIZE(dest, orig_len); 1994 | SET_VARSIZE(dest, orig_len + PGLZ_HDRSZ); 1995 | memcpy(PGLZ_RAWDATA(dest), VARDATA(source), orig_len); 1996 | } 1997 | 1998 | return dest; 1999 | } 2000 | 2001 | /* 2002 | * Decompress a compressed version of bytea into text. 2003 | */ 2004 | Datum 2005 | pglz_decompress_text(PG_FUNCTION_ARGS) 2006 | { 2007 | bytea *source = PG_GETARG_BYTEA_P(0); 2008 | 2009 | PG_RETURN_TEXT_P(PGLZDecompress((struct varlena *) source)); 2010 | } 2011 | 2012 | /* 2013 | * Decompress a compressed version of bytea into bytea. 2014 | */ 2015 | Datum 2016 | pglz_decompress_bytea(PG_FUNCTION_ARGS) 2017 | { 2018 | bytea *source = PG_GETARG_BYTEA_P(0); 2019 | 2020 | PG_RETURN_BYTEA_P(PGLZDecompress((struct varlena *) source)); 2021 | } 2022 | 2023 | /* 2024 | * Decompress a compressed version of a varlena datum. 2025 | */ 2026 | static struct varlena * 2027 | PGLZDecompress(struct varlena *source) 2028 | { 2029 | struct varlena *dest; 2030 | int32 orig_len = PGLZ_RAWSIZE(source); 2031 | 2032 | dest = (struct varlena *) palloc(orig_len + VARHDRSZ); 2033 | SET_VARSIZE(dest, orig_len + VARHDRSZ); 2034 | 2035 | if (!PGLZ_IS_COMPRESSED(source)) 2036 | memcpy(VARDATA(dest), PGLZ_RAWDATA(source), orig_len); 2037 | else 2038 | { 2039 | #if PG_VERSION_NUM >= 120000 2040 | if (pglz_decompress(PGLZ_RAWDATA(source), 2041 | VARSIZE(source) - PGLZ_HDRSZ, 2042 | VARDATA(dest), orig_len, true) < 0) 2043 | #else 2044 | if (pglz_decompress(PGLZ_RAWDATA(source), 2045 | VARSIZE(source) - PGLZ_HDRSZ, 2046 | VARDATA(dest), orig_len) < 0) 2047 | #endif 2048 | ereport(ERROR, 2049 | (errcode(ERRCODE_INVALID_PARAMETER_VALUE), 2050 | (errmsg("specified compressed data is corrupted"), 2051 | errhint("Make sure compressed data that pglz_compress or pglz_compress_bytea created is specified.")))); 2052 | } 2053 | 2054 | return dest; 2055 | } 2056 | #endif /* PG_VERSION_NUM >= 90500 */ 2057 | 2058 | #if PG_VERSION_NUM >= 100000 2059 | /* 2060 | * Normalize the input string with SASLprep. 2061 | */ 2062 | Datum 2063 | pg_cheat_saslprep(PG_FUNCTION_ARGS) 2064 | { 2065 | char *input = text_to_cstring(PG_GETARG_TEXT_P(0)); 2066 | char *output = NULL; 2067 | pg_saslprep_rc rc; 2068 | 2069 | rc = pg_saslprep(input, &output); 2070 | if (rc == SASLPREP_INVALID_UTF8) 2071 | ereport(ERROR, 2072 | (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), 2073 | (errmsg("input is not a valid UTF-8 string")))); 2074 | else if (rc == SASLPREP_PROHIBITED) 2075 | ereport(ERROR, 2076 | (errcode(ERRCODE_CHARACTER_NOT_IN_REPERTOIRE), 2077 | (errmsg("normalized string contains prohibited characters")))); 2078 | 2079 | PG_RETURN_TEXT_P(cstring_to_text(output)); 2080 | } 2081 | #endif 2082 | 2083 | /* 2084 | * Functions for manipulating advisory locks. 2085 | * These functions are borrowed from src/backend/utils/adt/lockfuncs.c. 2086 | */ 2087 | #define SET_LOCKTAG_INT64(tag, key64) \ 2088 | SET_LOCKTAG_ADVISORY(tag, \ 2089 | MyDatabaseId, \ 2090 | (uint32) ((key64) >> 32), \ 2091 | (uint32) (key64), \ 2092 | 1) 2093 | #define SET_LOCKTAG_INT32(tag, key1, key2) \ 2094 | SET_LOCKTAG_ADVISORY(tag, MyDatabaseId, key1, key2, 2) 2095 | 2096 | /* 2097 | * Release xact scoped exclusive lock an int8 key. 2098 | * 2099 | * Return true if successful, false if lock was not held. 2100 | */ 2101 | Datum 2102 | pg_advisory_xact_unlock_int8(PG_FUNCTION_ARGS) 2103 | { 2104 | int64 key = PG_GETARG_INT64(0); 2105 | LOCKTAG tag; 2106 | bool res; 2107 | 2108 | SET_LOCKTAG_INT64(tag, key); 2109 | 2110 | res = LockRelease(&tag, ExclusiveLock, false); 2111 | 2112 | PG_RETURN_BOOL(res); 2113 | } 2114 | 2115 | /* 2116 | * Release xact scoped share lock on an int8 key. 2117 | * 2118 | * Return true if successful, false if lock was not held. 2119 | */ 2120 | Datum 2121 | pg_advisory_xact_unlock_shared_int8(PG_FUNCTION_ARGS) 2122 | { 2123 | int64 key = PG_GETARG_INT64(0); 2124 | LOCKTAG tag; 2125 | bool res; 2126 | 2127 | SET_LOCKTAG_INT64(tag, key); 2128 | 2129 | res = LockRelease(&tag, ShareLock, false); 2130 | 2131 | PG_RETURN_BOOL(res); 2132 | } 2133 | 2134 | /* 2135 | * Release xact scoped exclusive lock on 2 int4 keys. 2136 | * 2137 | * Return true if successful, false if lock was not held. 2138 | */ 2139 | Datum 2140 | pg_advisory_xact_unlock_int4(PG_FUNCTION_ARGS) 2141 | { 2142 | int32 key1 = PG_GETARG_INT32(0); 2143 | int32 key2 = PG_GETARG_INT32(1); 2144 | LOCKTAG tag; 2145 | bool res; 2146 | 2147 | SET_LOCKTAG_INT32(tag, key1, key2); 2148 | 2149 | res = LockRelease(&tag, ExclusiveLock, false); 2150 | 2151 | PG_RETURN_BOOL(res); 2152 | } 2153 | 2154 | /* 2155 | * Release xact scoped share lock on 2 int4 keys. 2156 | * 2157 | * Return true if successful, false if lock was not held. 2158 | */ 2159 | Datum 2160 | pg_advisory_xact_unlock_shared_int4(PG_FUNCTION_ARGS) 2161 | { 2162 | int32 key1 = PG_GETARG_INT32(0); 2163 | int32 key2 = PG_GETARG_INT32(1); 2164 | LOCKTAG tag; 2165 | bool res; 2166 | 2167 | SET_LOCKTAG_INT32(tag, key1, key2); 2168 | 2169 | res = LockRelease(&tag, ShareLock, false); 2170 | 2171 | PG_RETURN_BOOL(res); 2172 | } 2173 | -------------------------------------------------------------------------------- /pg_cheat_funcs.control: -------------------------------------------------------------------------------- 1 | # pg_cheat_funcs extension 2 | comment = 'provides cheat (but useful) functions' 3 | default_version = '1.0' 4 | module_pathname = '$libdir/pg_cheat_funcs' 5 | relocatable = true 6 | -------------------------------------------------------------------------------- /sql/pg_94_or_later.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | CREATE TABLE test_lsn (lsn pg_lsn); 6 | INSERT INTO test_lsn VALUES ('0/A'), ('0/1000'), ('DA3/15A4D10'), ('E4/A0422B68'), ('447/F6D166E8'); 7 | SELECT min(lsn), max(lsn) FROM test_lsn; 8 | 9 | SELECT pg_file_fsync('global'); 10 | SELECT pg_file_fsync('global/pg_control'); 11 | 12 | BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; 13 | SELECT pg_refresh_snapshot(); 14 | SELECT 1; 15 | SELECT pg_refresh_snapshot(); 16 | COMMIT; 17 | 18 | DROP EXTENSION pg_cheat_funcs; 19 | -------------------------------------------------------------------------------- /sql/pg_advance_vacuum_cleanup_age.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | DO $$ 6 | DECLARE 7 | orig_cleanup_age text := current_setting('vacuum_defer_cleanup_age'); 8 | BEGIN 9 | PERFORM pg_advance_vacuum_cleanup_age(99); 10 | IF current_setting('vacuum_defer_cleanup_age') <> '-99' THEN 11 | RAISE WARNING 'could not advance vacuum cleanup age properly.'; 12 | END IF; 13 | PERFORM pg_advance_vacuum_cleanup_age(); 14 | IF current_setting('vacuum_defer_cleanup_age') <> orig_cleanup_age THEN 15 | RAISE NOTICE 'could not reset vacuum cleanup age properly.'; 16 | END IF; 17 | END; 18 | $$ LANGUAGE plpgsql; 19 | 20 | DROP EXTENSION pg_cheat_funcs; 21 | -------------------------------------------------------------------------------- /sql/pg_cached_plan.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | PREPARE stmt AS SELECT * FROM pg_database WHERE datname = $1; 6 | SELECT * FROM pg_cached_plan_source('stmt'); 7 | 8 | DROP EXTENSION pg_cheat_funcs; 9 | -------------------------------------------------------------------------------- /sql/pg_cheat_funcs.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | SELECT pg_signal_process(pg_postmaster_pid(), 'HUP'); 6 | 7 | SET pg_cheat_funcs.scheduling_priority TO 1; 8 | SELECT pg_get_priority(pg_backend_pid()); 9 | SELECT pg_set_priority(pg_backend_pid(), 2); 10 | SHOW pg_cheat_funcs.scheduling_priority; 11 | 12 | SELECT pg_eucjp('xa4', 'xa2'); 13 | 14 | SELECT pg_set_next_xid(next_xid) = next_xid FROM pg_xid_assignment(); 15 | 16 | SELECT to_octal(num) FROM generate_series(1, 10) num; 17 | SELECT to_octal(2147483647::integer); 18 | SELECT to_octal(9223372036854775807::bigint); 19 | 20 | SELECT pg_text_to_hex('PostgreSQL'); 21 | SELECT pg_hex_to_text('506f737467726553514c'); 22 | SELECT pg_hex_to_text(upper('506f737467726553514c')); 23 | 24 | SELECT pg_backend_start_time() = backend_start FROM pg_stat_get_activity(pg_backend_pid()); 25 | 26 | SELECT substring(pg_tablespace_version_directory(), 1, 3); 27 | 28 | BEGIN; 29 | SELECT pg_advisory_xact_lock(111); 30 | SELECT pg_advisory_xact_lock(222); 31 | SELECT pg_advisory_xact_lock_shared(333); 32 | SELECT pg_advisory_xact_lock(444, 555); 33 | SELECT pg_advisory_xact_lock_shared(666, 777); 34 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 35 | SELECT pg_advisory_xact_unlock(111); 36 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 37 | SELECT pg_advisory_xact_unlock_shared(666, 777); 38 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 39 | COMMIT; 40 | SELECT classid, objid, objsubid, mode FROM pg_locks WHERE locktype = 'advisory' ORDER BY classid, objid, objsubid, mode; 41 | 42 | -- SET pg_cheat_funcs.exit_on_segv TO on; 43 | -- SELECT pg_segmentation_fault(true); 44 | -- SET pg_cheat_funcs.exit_on_segv TO off; 45 | 46 | DROP EXTENSION pg_cheat_funcs; 47 | -------------------------------------------------------------------------------- /sql/pg_chr.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | SELECT chr(88) = pg_chr(88); 6 | SELECT chr(12354) = pg_chr(12354); 7 | SELECT chr(57000); 8 | SELECT pg_chr(57000); 9 | SELECT chr(2000000); 10 | SELECT pg_chr(2000000); 11 | SELECT pg_chr(code) FROM generate_series(57000, 57010) code; 12 | 13 | DROP EXTENSION pg_cheat_funcs; 14 | -------------------------------------------------------------------------------- /sql/pg_chr_91_93.sql: -------------------------------------------------------------------------------- 1 | \i sql/pg_chr.sql 2 | -------------------------------------------------------------------------------- /sql/pg_eucjp.sql: -------------------------------------------------------------------------------- 1 | -- clean-up in case a prior regression run failed 2 | SET client_min_messages TO 'warning'; 3 | DROP DATABASE IF EXISTS regtest_cheat_funcs_eucjp; 4 | RESET client_min_messages; 5 | 6 | CREATE DATABASE regtest_cheat_funcs_eucjp ENCODING 'EUC_JP' LC_COLLATE 'C' LC_CTYPE 'C' TEMPLATE template0; 7 | \c regtest_cheat_funcs_eucjp 8 | 9 | SET client_encoding TO 'EUC_JP'; 10 | 11 | CREATE EXTENSION pg_cheat_funcs; 12 | 13 | \pset null '(null)' 14 | 15 | SELECT pg_eucjp(65::bit(8)); 16 | SELECT pg_eucjp(65::bit(8), 65::bit(8)); 17 | 18 | SELECT pg_eucjp('xa4', 'xca'); 19 | SELECT pg_eucjp('xa4', 'xca', 'xca'); 20 | SELECT pg_eucjp('xa0', 'xca'); 21 | SELECT pg_eucjp('xa4', 'xff'); 22 | 23 | SELECT pg_eucjp('x8e', 'xc5'); 24 | SELECT pg_eucjp('x8e', 'xc5', 'xc5'); 25 | SELECT pg_eucjp('x8e', 'xe0'); 26 | 27 | SELECT pg_eucjp('x8f', 'xa2', 'xee'); 28 | SELECT pg_eucjp('x8f', 'xa0', 'xee'); 29 | SELECT pg_eucjp('x8f', 'xa2', 'xff'); 30 | 31 | CREATE TABLE all_eucjp(code1 text, code2 text, code3 text, eucjp text); 32 | INSERT INTO all_eucjp SELECT * FROM pg_all_eucjp(); 33 | SELECT count(*) FROM all_eucjp 34 | WHERE pg_eucjp(code1::bit(8), code2::bit(8), code3::bit(8)) <> eucjp; 35 | SELECT * FROM all_eucjp ORDER BY code1, code2, code3; 36 | 37 | SELECT pg_eucjp('xb6', 'xe5') || pg_eucjp('xfc', 'xf9') || pg_eucjp('xad', 'xa9') || pg_eucjp('xfa', 'xdb'); 38 | 39 | UPDATE pg_conversion SET condefault = 'f' WHERE conname = 'euc_jp_to_utf8'; 40 | UPDATE pg_conversion SET condefault = 't' WHERE conname = 'pg_euc_jp_to_utf8'; 41 | \c regtest_cheat_funcs_eucjp 42 | 43 | SET client_encoding TO 'UTF-8'; 44 | SELECT pg_eucjp('xb6', 'xe5') || pg_eucjp('xfc', 'xf9') || pg_eucjp('xad', 'xa9') || pg_eucjp('xfa', 'xdb'); 45 | 46 | DROP EXTENSION pg_cheat_funcs; 47 | 48 | \c contrib_regression 49 | DROP DATABASE regtest_cheat_funcs_eucjp; 50 | -------------------------------------------------------------------------------- /sql/pg_saslprep.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | SELECT pg_saslprep(chr(8470) || chr(9316) || '4' || chr(12892)); 6 | 7 | DROP EXTENSION pg_cheat_funcs; 8 | -------------------------------------------------------------------------------- /sql/pg_stat_get_memory_context.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | SELECT name FROM pg_stat_get_memory_context() WHERE parent IS NULL; 6 | 7 | DROP EXTENSION pg_cheat_funcs; 8 | -------------------------------------------------------------------------------- /sql/pg_stat_print_memory_context.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | SELECT pg_stat_print_memory_context(); 6 | 7 | DROP EXTENSION pg_cheat_funcs; 8 | -------------------------------------------------------------------------------- /sql/pg_xid_to_xid8.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | BEGIN; 6 | SELECT 1 FROM pg_current_xact_id(); 7 | SELECT pg_current_xact_id() = pg_xid_to_xid8(backend_xid) 8 | FROM pg_stat_activity WHERE pid = pg_backend_pid(); 9 | COMMIT; 10 | 11 | DROP EXTENSION pg_cheat_funcs; 12 | -------------------------------------------------------------------------------- /sql/pglz_compress.sql: -------------------------------------------------------------------------------- 1 | CREATE EXTENSION pg_cheat_funcs; 2 | 3 | \pset null '(null)' 4 | 5 | SELECT lz, aa, pglz_decompress(lz), aa::bytea, pglz_decompress_bytea(lz) 6 | FROM (SELECT aa, pglz_compress(aa) lz FROM repeat('A', 2) aa) hoge; 7 | SELECT lz, aa, pglz_decompress(lz), aa::bytea, pglz_decompress_bytea(lz) 8 | FROM (SELECT aa, pglz_compress(aa) lz FROM repeat('A', 32) aa) hoge; 9 | 10 | SELECT lz, aa, pglz_decompress_bytea(lz), pglz_decompress(lz) 11 | FROM (SELECT aa::bytea, pglz_compress_bytea(aa::bytea) lz FROM repeat('A', 2) aa) hoge; 12 | SELECT lz, aa, pglz_decompress_bytea(lz), pglz_decompress(lz) 13 | FROM (SELECT aa::bytea, pglz_compress_bytea(aa::bytea) lz FROM repeat('A', 32) aa) hoge; 14 | 15 | DROP EXTENSION pg_cheat_funcs; 16 | --------------------------------------------------------------------------------