PageRenderTime 65ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/bin/psql/tab-complete.c

https://github.com/larkly/postgres-docker
C | 4352 lines | 3625 code | 266 blank | 461 comment | 1092 complexity | bd95d0eaeff396c9dcede159ecb1fe98 MD5 | raw file
Possible License(s): AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * psql - the PostgreSQL interactive terminal
  3. *
  4. * Copyright (c) 2000-2014, PostgreSQL Global Development Group
  5. *
  6. * src/bin/psql/tab-complete.c
  7. */
  8. /*----------------------------------------------------------------------
  9. * This file implements a somewhat more sophisticated readline "TAB
  10. * completion" in psql. It is not intended to be AI, to replace
  11. * learning SQL, or to relieve you from thinking about what you're
  12. * doing. Also it does not always give you all the syntactically legal
  13. * completions, only those that are the most common or the ones that
  14. * the programmer felt most like implementing.
  15. *
  16. * CAVEAT: Tab completion causes queries to be sent to the backend.
  17. * The number of tuples returned gets limited, in most default
  18. * installations to 1000, but if you still don't like this prospect,
  19. * you can turn off tab completion in your ~/.inputrc (or else
  20. * ${INPUTRC}) file so:
  21. *
  22. * $if psql
  23. * set disable-completion on
  24. * $endif
  25. *
  26. * See `man 3 readline' or `info readline' for the full details. Also,
  27. * hence the
  28. *
  29. * BUGS:
  30. *
  31. * - If you split your queries across lines, this whole thing gets
  32. * confused. (To fix this, one would have to read psql's query
  33. * buffer rather than readline's line buffer, which would require
  34. * some major revisions of things.)
  35. *
  36. * - Table or attribute names with spaces in it may confuse it.
  37. *
  38. * - Quotes, parenthesis, and other funny characters are not handled
  39. * all that gracefully.
  40. *----------------------------------------------------------------------
  41. */
  42. #include "postgres_fe.h"
  43. #include "tab-complete.h"
  44. #include "input.h"
  45. /* If we don't have this, we might as well forget about the whole thing: */
  46. #ifdef USE_READLINE
  47. #include <ctype.h>
  48. #include "libpq-fe.h"
  49. #include "pqexpbuffer.h"
  50. #include "common.h"
  51. #include "settings.h"
  52. #include "stringutils.h"
  53. #ifdef HAVE_RL_FILENAME_COMPLETION_FUNCTION
  54. #define filename_completion_function rl_filename_completion_function
  55. #else
  56. /* missing in some header files */
  57. extern char *filename_completion_function();
  58. #endif
  59. #ifdef HAVE_RL_COMPLETION_MATCHES
  60. #define completion_matches rl_completion_matches
  61. #endif
  62. /* word break characters */
  63. #define WORD_BREAKS "\t\n@$><=;|&{() "
  64. /*
  65. * This struct is used to define "schema queries", which are custom-built
  66. * to obtain possibly-schema-qualified names of database objects. There is
  67. * enough similarity in the structure that we don't want to repeat it each
  68. * time. So we put the components of each query into this struct and
  69. * assemble them with the common boilerplate in _complete_from_query().
  70. */
  71. typedef struct SchemaQuery
  72. {
  73. /*
  74. * Name of catalog or catalogs to be queried, with alias, eg.
  75. * "pg_catalog.pg_class c". Note that "pg_namespace n" will be added.
  76. */
  77. const char *catname;
  78. /*
  79. * Selection condition --- only rows meeting this condition are candidates
  80. * to display. If catname mentions multiple tables, include the necessary
  81. * join condition here. For example, "c.relkind = 'r'". Write NULL (not
  82. * an empty string) if not needed.
  83. */
  84. const char *selcondition;
  85. /*
  86. * Visibility condition --- which rows are visible without schema
  87. * qualification? For example, "pg_catalog.pg_table_is_visible(c.oid)".
  88. */
  89. const char *viscondition;
  90. /*
  91. * Namespace --- name of field to join to pg_namespace.oid. For example,
  92. * "c.relnamespace".
  93. */
  94. const char *namespace;
  95. /*
  96. * Result --- the appropriately-quoted name to return, in the case of an
  97. * unqualified name. For example, "pg_catalog.quote_ident(c.relname)".
  98. */
  99. const char *result;
  100. /*
  101. * In some cases a different result must be used for qualified names.
  102. * Enter that here, or write NULL if result can be used.
  103. */
  104. const char *qualresult;
  105. } SchemaQuery;
  106. /* Store maximum number of records we want from database queries
  107. * (implemented via SELECT ... LIMIT xx).
  108. */
  109. static int completion_max_records;
  110. /*
  111. * Communication variables set by COMPLETE_WITH_FOO macros and then used by
  112. * the completion callback functions. Ugly but there is no better way.
  113. */
  114. static const char *completion_charp; /* to pass a string */
  115. static const char *const * completion_charpp; /* to pass a list of strings */
  116. static const char *completion_info_charp; /* to pass a second string */
  117. static const char *completion_info_charp2; /* to pass a third string */
  118. static const SchemaQuery *completion_squery; /* to pass a SchemaQuery */
  119. static bool completion_case_sensitive; /* completion is case sensitive */
  120. /*
  121. * A few macros to ease typing. You can use these to complete the given
  122. * string with
  123. * 1) The results from a query you pass it. (Perhaps one of those below?)
  124. * 2) The results from a schema query you pass it.
  125. * 3) The items from a null-pointer-terminated list.
  126. * 4) A string constant.
  127. * 5) The list of attributes of the given table (possibly schema-qualified).
  128. * 6/ The list of arguments to the given function (possibly schema-qualified).
  129. */
  130. #define COMPLETE_WITH_QUERY(query) \
  131. do { \
  132. completion_charp = query; \
  133. matches = completion_matches(text, complete_from_query); \
  134. } while (0)
  135. #define COMPLETE_WITH_SCHEMA_QUERY(query, addon) \
  136. do { \
  137. completion_squery = &(query); \
  138. completion_charp = addon; \
  139. matches = completion_matches(text, complete_from_schema_query); \
  140. } while (0)
  141. #define COMPLETE_WITH_LIST_CS(list) \
  142. do { \
  143. completion_charpp = list; \
  144. completion_case_sensitive = true; \
  145. matches = completion_matches(text, complete_from_list); \
  146. } while (0)
  147. #define COMPLETE_WITH_LIST(list) \
  148. do { \
  149. completion_charpp = list; \
  150. completion_case_sensitive = false; \
  151. matches = completion_matches(text, complete_from_list); \
  152. } while (0)
  153. #define COMPLETE_WITH_CONST(string) \
  154. do { \
  155. completion_charp = string; \
  156. completion_case_sensitive = false; \
  157. matches = completion_matches(text, complete_from_const); \
  158. } while (0)
  159. #define COMPLETE_WITH_ATTR(relation, addon) \
  160. do { \
  161. char *_completion_schema; \
  162. char *_completion_table; \
  163. \
  164. _completion_schema = strtokx(relation, " \t\n\r", ".", "\"", 0, \
  165. false, false, pset.encoding); \
  166. (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
  167. false, false, pset.encoding); \
  168. _completion_table = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
  169. false, false, pset.encoding); \
  170. if (_completion_table == NULL) \
  171. { \
  172. completion_charp = Query_for_list_of_attributes addon; \
  173. completion_info_charp = relation; \
  174. } \
  175. else \
  176. { \
  177. completion_charp = Query_for_list_of_attributes_with_schema addon; \
  178. completion_info_charp = _completion_table; \
  179. completion_info_charp2 = _completion_schema; \
  180. } \
  181. matches = completion_matches(text, complete_from_query); \
  182. } while (0)
  183. #define COMPLETE_WITH_FUNCTION_ARG(function) \
  184. do { \
  185. char *_completion_schema; \
  186. char *_completion_function; \
  187. \
  188. _completion_schema = strtokx(function, " \t\n\r", ".", "\"", 0, \
  189. false, false, pset.encoding); \
  190. (void) strtokx(NULL, " \t\n\r", ".", "\"", 0, \
  191. false, false, pset.encoding); \
  192. _completion_function = strtokx(NULL, " \t\n\r", ".", "\"", 0, \
  193. false, false, pset.encoding); \
  194. if (_completion_function == NULL) \
  195. { \
  196. completion_charp = Query_for_list_of_arguments; \
  197. completion_info_charp = function; \
  198. } \
  199. else \
  200. { \
  201. completion_charp = Query_for_list_of_arguments_with_schema; \
  202. completion_info_charp = _completion_function; \
  203. completion_info_charp2 = _completion_schema; \
  204. } \
  205. matches = completion_matches(text, complete_from_query); \
  206. } while (0)
  207. /*
  208. * Assembly instructions for schema queries
  209. */
  210. static const SchemaQuery Query_for_list_of_aggregates = {
  211. /* catname */
  212. "pg_catalog.pg_proc p",
  213. /* selcondition */
  214. "p.proisagg",
  215. /* viscondition */
  216. "pg_catalog.pg_function_is_visible(p.oid)",
  217. /* namespace */
  218. "p.pronamespace",
  219. /* result */
  220. "pg_catalog.quote_ident(p.proname)",
  221. /* qualresult */
  222. NULL
  223. };
  224. static const SchemaQuery Query_for_list_of_datatypes = {
  225. /* catname */
  226. "pg_catalog.pg_type t",
  227. /* selcondition --- ignore table rowtypes and array types */
  228. "(t.typrelid = 0 "
  229. " OR (SELECT c.relkind = 'c' FROM pg_catalog.pg_class c WHERE c.oid = t.typrelid)) "
  230. "AND t.typname !~ '^_'",
  231. /* viscondition */
  232. "pg_catalog.pg_type_is_visible(t.oid)",
  233. /* namespace */
  234. "t.typnamespace",
  235. /* result */
  236. "pg_catalog.format_type(t.oid, NULL)",
  237. /* qualresult */
  238. "pg_catalog.quote_ident(t.typname)"
  239. };
  240. static const SchemaQuery Query_for_list_of_domains = {
  241. /* catname */
  242. "pg_catalog.pg_type t",
  243. /* selcondition */
  244. "t.typtype = 'd'",
  245. /* viscondition */
  246. "pg_catalog.pg_type_is_visible(t.oid)",
  247. /* namespace */
  248. "t.typnamespace",
  249. /* result */
  250. "pg_catalog.quote_ident(t.typname)",
  251. /* qualresult */
  252. NULL
  253. };
  254. static const SchemaQuery Query_for_list_of_functions = {
  255. /* catname */
  256. "pg_catalog.pg_proc p",
  257. /* selcondition */
  258. NULL,
  259. /* viscondition */
  260. "pg_catalog.pg_function_is_visible(p.oid)",
  261. /* namespace */
  262. "p.pronamespace",
  263. /* result */
  264. "pg_catalog.quote_ident(p.proname)",
  265. /* qualresult */
  266. NULL
  267. };
  268. static const SchemaQuery Query_for_list_of_indexes = {
  269. /* catname */
  270. "pg_catalog.pg_class c",
  271. /* selcondition */
  272. "c.relkind IN ('i')",
  273. /* viscondition */
  274. "pg_catalog.pg_table_is_visible(c.oid)",
  275. /* namespace */
  276. "c.relnamespace",
  277. /* result */
  278. "pg_catalog.quote_ident(c.relname)",
  279. /* qualresult */
  280. NULL
  281. };
  282. static const SchemaQuery Query_for_list_of_sequences = {
  283. /* catname */
  284. "pg_catalog.pg_class c",
  285. /* selcondition */
  286. "c.relkind IN ('S')",
  287. /* viscondition */
  288. "pg_catalog.pg_table_is_visible(c.oid)",
  289. /* namespace */
  290. "c.relnamespace",
  291. /* result */
  292. "pg_catalog.quote_ident(c.relname)",
  293. /* qualresult */
  294. NULL
  295. };
  296. static const SchemaQuery Query_for_list_of_foreign_tables = {
  297. /* catname */
  298. "pg_catalog.pg_class c",
  299. /* selcondition */
  300. "c.relkind IN ('f')",
  301. /* viscondition */
  302. "pg_catalog.pg_table_is_visible(c.oid)",
  303. /* namespace */
  304. "c.relnamespace",
  305. /* result */
  306. "pg_catalog.quote_ident(c.relname)",
  307. /* qualresult */
  308. NULL
  309. };
  310. static const SchemaQuery Query_for_list_of_tables = {
  311. /* catname */
  312. "pg_catalog.pg_class c",
  313. /* selcondition */
  314. "c.relkind IN ('r')",
  315. /* viscondition */
  316. "pg_catalog.pg_table_is_visible(c.oid)",
  317. /* namespace */
  318. "c.relnamespace",
  319. /* result */
  320. "pg_catalog.quote_ident(c.relname)",
  321. /* qualresult */
  322. NULL
  323. };
  324. static const SchemaQuery Query_for_list_of_constraints_with_schema = {
  325. /* catname */
  326. "pg_catalog.pg_constraint c",
  327. /* selcondition */
  328. "c.conrelid <> 0",
  329. /* viscondition */
  330. "true", /* there is no pg_constraint_is_visible */
  331. /* namespace */
  332. "c.connamespace",
  333. /* result */
  334. "pg_catalog.quote_ident(c.conname)",
  335. /* qualresult */
  336. NULL
  337. };
  338. /* Relations supporting INSERT, UPDATE or DELETE */
  339. static const SchemaQuery Query_for_list_of_updatables = {
  340. /* catname */
  341. "pg_catalog.pg_class c",
  342. /* selcondition */
  343. "c.relkind IN ('r', 'f', 'v')",
  344. /* viscondition */
  345. "pg_catalog.pg_table_is_visible(c.oid)",
  346. /* namespace */
  347. "c.relnamespace",
  348. /* result */
  349. "pg_catalog.quote_ident(c.relname)",
  350. /* qualresult */
  351. NULL
  352. };
  353. static const SchemaQuery Query_for_list_of_relations = {
  354. /* catname */
  355. "pg_catalog.pg_class c",
  356. /* selcondition */
  357. NULL,
  358. /* viscondition */
  359. "pg_catalog.pg_table_is_visible(c.oid)",
  360. /* namespace */
  361. "c.relnamespace",
  362. /* result */
  363. "pg_catalog.quote_ident(c.relname)",
  364. /* qualresult */
  365. NULL
  366. };
  367. static const SchemaQuery Query_for_list_of_tsvmf = {
  368. /* catname */
  369. "pg_catalog.pg_class c",
  370. /* selcondition */
  371. "c.relkind IN ('r', 'S', 'v', 'm', 'f')",
  372. /* viscondition */
  373. "pg_catalog.pg_table_is_visible(c.oid)",
  374. /* namespace */
  375. "c.relnamespace",
  376. /* result */
  377. "pg_catalog.quote_ident(c.relname)",
  378. /* qualresult */
  379. NULL
  380. };
  381. static const SchemaQuery Query_for_list_of_tmf = {
  382. /* catname */
  383. "pg_catalog.pg_class c",
  384. /* selcondition */
  385. "c.relkind IN ('r', 'm', 'f')",
  386. /* viscondition */
  387. "pg_catalog.pg_table_is_visible(c.oid)",
  388. /* namespace */
  389. "c.relnamespace",
  390. /* result */
  391. "pg_catalog.quote_ident(c.relname)",
  392. /* qualresult */
  393. NULL
  394. };
  395. static const SchemaQuery Query_for_list_of_tm = {
  396. /* catname */
  397. "pg_catalog.pg_class c",
  398. /* selcondition */
  399. "c.relkind IN ('r', 'm')",
  400. /* viscondition */
  401. "pg_catalog.pg_table_is_visible(c.oid)",
  402. /* namespace */
  403. "c.relnamespace",
  404. /* result */
  405. "pg_catalog.quote_ident(c.relname)",
  406. /* qualresult */
  407. NULL
  408. };
  409. static const SchemaQuery Query_for_list_of_views = {
  410. /* catname */
  411. "pg_catalog.pg_class c",
  412. /* selcondition */
  413. "c.relkind IN ('v')",
  414. /* viscondition */
  415. "pg_catalog.pg_table_is_visible(c.oid)",
  416. /* namespace */
  417. "c.relnamespace",
  418. /* result */
  419. "pg_catalog.quote_ident(c.relname)",
  420. /* qualresult */
  421. NULL
  422. };
  423. static const SchemaQuery Query_for_list_of_matviews = {
  424. /* catname */
  425. "pg_catalog.pg_class c",
  426. /* selcondition */
  427. "c.relkind IN ('m')",
  428. /* viscondition */
  429. "pg_catalog.pg_table_is_visible(c.oid)",
  430. /* namespace */
  431. "c.relnamespace",
  432. /* result */
  433. "pg_catalog.quote_ident(c.relname)",
  434. /* qualresult */
  435. NULL
  436. };
  437. /*
  438. * Queries to get lists of names of various kinds of things, possibly
  439. * restricted to names matching a partially entered name. In these queries,
  440. * the first %s will be replaced by the text entered so far (suitably escaped
  441. * to become a SQL literal string). %d will be replaced by the length of the
  442. * string (in unescaped form). A second and third %s, if present, will be
  443. * replaced by a suitably-escaped version of the string provided in
  444. * completion_info_charp. A fourth and fifth %s are similarly replaced by
  445. * completion_info_charp2.
  446. *
  447. * Beware that the allowed sequences of %s and %d are determined by
  448. * _complete_from_query().
  449. */
  450. #define Query_for_list_of_attributes \
  451. "SELECT pg_catalog.quote_ident(attname) "\
  452. " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c "\
  453. " WHERE c.oid = a.attrelid "\
  454. " AND a.attnum > 0 "\
  455. " AND NOT a.attisdropped "\
  456. " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
  457. " AND (pg_catalog.quote_ident(relname)='%s' "\
  458. " OR '\"' || relname || '\"'='%s') "\
  459. " AND pg_catalog.pg_table_is_visible(c.oid)"
  460. #define Query_for_list_of_attributes_with_schema \
  461. "SELECT pg_catalog.quote_ident(attname) "\
  462. " FROM pg_catalog.pg_attribute a, pg_catalog.pg_class c, pg_catalog.pg_namespace n "\
  463. " WHERE c.oid = a.attrelid "\
  464. " AND n.oid = c.relnamespace "\
  465. " AND a.attnum > 0 "\
  466. " AND NOT a.attisdropped "\
  467. " AND substring(pg_catalog.quote_ident(attname),1,%d)='%s' "\
  468. " AND (pg_catalog.quote_ident(relname)='%s' "\
  469. " OR '\"' || relname || '\"' ='%s') "\
  470. " AND (pg_catalog.quote_ident(nspname)='%s' "\
  471. " OR '\"' || nspname || '\"' ='%s') "
  472. #define Query_for_list_of_template_databases \
  473. "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
  474. " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s' AND datistemplate"
  475. #define Query_for_list_of_databases \
  476. "SELECT pg_catalog.quote_ident(datname) FROM pg_catalog.pg_database "\
  477. " WHERE substring(pg_catalog.quote_ident(datname),1,%d)='%s'"
  478. #define Query_for_list_of_tablespaces \
  479. "SELECT pg_catalog.quote_ident(spcname) FROM pg_catalog.pg_tablespace "\
  480. " WHERE substring(pg_catalog.quote_ident(spcname),1,%d)='%s'"
  481. #define Query_for_list_of_encodings \
  482. " SELECT DISTINCT pg_catalog.pg_encoding_to_char(conforencoding) "\
  483. " FROM pg_catalog.pg_conversion "\
  484. " WHERE substring(pg_catalog.pg_encoding_to_char(conforencoding),1,%d)=UPPER('%s')"
  485. #define Query_for_list_of_languages \
  486. "SELECT pg_catalog.quote_ident(lanname) "\
  487. " FROM pg_catalog.pg_language "\
  488. " WHERE lanname != 'internal' "\
  489. " AND substring(pg_catalog.quote_ident(lanname),1,%d)='%s'"
  490. #define Query_for_list_of_schemas \
  491. "SELECT pg_catalog.quote_ident(nspname) FROM pg_catalog.pg_namespace "\
  492. " WHERE substring(pg_catalog.quote_ident(nspname),1,%d)='%s'"
  493. #define Query_for_list_of_alter_system_set_vars \
  494. "SELECT name FROM "\
  495. " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
  496. " WHERE context != 'internal') ss "\
  497. " WHERE substring(name,1,%d)='%s'"
  498. #define Query_for_list_of_set_vars \
  499. "SELECT name FROM "\
  500. " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
  501. " WHERE context IN ('user', 'superuser') "\
  502. " UNION ALL SELECT 'constraints' "\
  503. " UNION ALL SELECT 'transaction' "\
  504. " UNION ALL SELECT 'session' "\
  505. " UNION ALL SELECT 'role' "\
  506. " UNION ALL SELECT 'tablespace' "\
  507. " UNION ALL SELECT 'all') ss "\
  508. " WHERE substring(name,1,%d)='%s'"
  509. #define Query_for_list_of_show_vars \
  510. "SELECT name FROM "\
  511. " (SELECT pg_catalog.lower(name) AS name FROM pg_catalog.pg_settings "\
  512. " UNION ALL SELECT 'session authorization' "\
  513. " UNION ALL SELECT 'all') ss "\
  514. " WHERE substring(name,1,%d)='%s'"
  515. #define Query_for_list_of_roles \
  516. " SELECT pg_catalog.quote_ident(rolname) "\
  517. " FROM pg_catalog.pg_roles "\
  518. " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"
  519. #define Query_for_list_of_grant_roles \
  520. " SELECT pg_catalog.quote_ident(rolname) "\
  521. " FROM pg_catalog.pg_roles "\
  522. " WHERE substring(pg_catalog.quote_ident(rolname),1,%d)='%s'"\
  523. " UNION ALL SELECT 'PUBLIC'"
  524. /* the silly-looking length condition is just to eat up the current word */
  525. #define Query_for_table_owning_index \
  526. "SELECT pg_catalog.quote_ident(c1.relname) "\
  527. " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
  528. " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
  529. " and (%d = pg_catalog.length('%s'))"\
  530. " and pg_catalog.quote_ident(c2.relname)='%s'"\
  531. " and pg_catalog.pg_table_is_visible(c2.oid)"
  532. /* the silly-looking length condition is just to eat up the current word */
  533. #define Query_for_index_of_table \
  534. "SELECT pg_catalog.quote_ident(c2.relname) "\
  535. " FROM pg_catalog.pg_class c1, pg_catalog.pg_class c2, pg_catalog.pg_index i"\
  536. " WHERE c1.oid=i.indrelid and i.indexrelid=c2.oid"\
  537. " and (%d = pg_catalog.length('%s'))"\
  538. " and pg_catalog.quote_ident(c1.relname)='%s'"\
  539. " and pg_catalog.pg_table_is_visible(c2.oid)"
  540. /* the silly-looking length condition is just to eat up the current word */
  541. #define Query_for_constraint_of_table \
  542. "SELECT pg_catalog.quote_ident(conname) "\
  543. " FROM pg_catalog.pg_class c1, pg_catalog.pg_constraint con "\
  544. " WHERE c1.oid=conrelid and (%d = pg_catalog.length('%s'))"\
  545. " and pg_catalog.quote_ident(c1.relname)='%s'"\
  546. " and pg_catalog.pg_table_is_visible(c1.oid)"
  547. #define Query_for_all_table_constraints \
  548. "SELECT pg_catalog.quote_ident(conname) "\
  549. " FROM pg_catalog.pg_constraint c "\
  550. " WHERE c.conrelid <> 0 "
  551. /* the silly-looking length condition is just to eat up the current word */
  552. #define Query_for_constraint_of_type \
  553. "SELECT pg_catalog.quote_ident(conname) "\
  554. " FROM pg_catalog.pg_type t, pg_catalog.pg_constraint con "\
  555. " WHERE t.oid=contypid and (%d = pg_catalog.length('%s'))"\
  556. " and pg_catalog.quote_ident(t.typname)='%s'"\
  557. " and pg_catalog.pg_type_is_visible(t.oid)"
  558. /* the silly-looking length condition is just to eat up the current word */
  559. #define Query_for_list_of_tables_for_constraint \
  560. "SELECT pg_catalog.quote_ident(relname) "\
  561. " FROM pg_catalog.pg_class"\
  562. " WHERE (%d = pg_catalog.length('%s'))"\
  563. " AND oid IN "\
  564. " (SELECT conrelid FROM pg_catalog.pg_constraint "\
  565. " WHERE pg_catalog.quote_ident(conname)='%s')"
  566. /* the silly-looking length condition is just to eat up the current word */
  567. #define Query_for_rule_of_table \
  568. "SELECT pg_catalog.quote_ident(rulename) "\
  569. " FROM pg_catalog.pg_class c1, pg_catalog.pg_rewrite "\
  570. " WHERE c1.oid=ev_class and (%d = pg_catalog.length('%s'))"\
  571. " and pg_catalog.quote_ident(c1.relname)='%s'"\
  572. " and pg_catalog.pg_table_is_visible(c1.oid)"
  573. /* the silly-looking length condition is just to eat up the current word */
  574. #define Query_for_list_of_tables_for_rule \
  575. "SELECT pg_catalog.quote_ident(relname) "\
  576. " FROM pg_catalog.pg_class"\
  577. " WHERE (%d = pg_catalog.length('%s'))"\
  578. " AND oid IN "\
  579. " (SELECT ev_class FROM pg_catalog.pg_rewrite "\
  580. " WHERE pg_catalog.quote_ident(rulename)='%s')"
  581. /* the silly-looking length condition is just to eat up the current word */
  582. #define Query_for_trigger_of_table \
  583. "SELECT pg_catalog.quote_ident(tgname) "\
  584. " FROM pg_catalog.pg_class c1, pg_catalog.pg_trigger "\
  585. " WHERE c1.oid=tgrelid and (%d = pg_catalog.length('%s'))"\
  586. " and pg_catalog.quote_ident(c1.relname)='%s'"\
  587. " and pg_catalog.pg_table_is_visible(c1.oid)"\
  588. " and not tgisinternal"
  589. /* the silly-looking length condition is just to eat up the current word */
  590. #define Query_for_list_of_tables_for_trigger \
  591. "SELECT pg_catalog.quote_ident(relname) "\
  592. " FROM pg_catalog.pg_class"\
  593. " WHERE (%d = pg_catalog.length('%s'))"\
  594. " AND oid IN "\
  595. " (SELECT tgrelid FROM pg_catalog.pg_trigger "\
  596. " WHERE pg_catalog.quote_ident(tgname)='%s')"
  597. #define Query_for_list_of_ts_configurations \
  598. "SELECT pg_catalog.quote_ident(cfgname) FROM pg_catalog.pg_ts_config "\
  599. " WHERE substring(pg_catalog.quote_ident(cfgname),1,%d)='%s'"
  600. #define Query_for_list_of_ts_dictionaries \
  601. "SELECT pg_catalog.quote_ident(dictname) FROM pg_catalog.pg_ts_dict "\
  602. " WHERE substring(pg_catalog.quote_ident(dictname),1,%d)='%s'"
  603. #define Query_for_list_of_ts_parsers \
  604. "SELECT pg_catalog.quote_ident(prsname) FROM pg_catalog.pg_ts_parser "\
  605. " WHERE substring(pg_catalog.quote_ident(prsname),1,%d)='%s'"
  606. #define Query_for_list_of_ts_templates \
  607. "SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
  608. " WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
  609. #define Query_for_list_of_fdws \
  610. " SELECT pg_catalog.quote_ident(fdwname) "\
  611. " FROM pg_catalog.pg_foreign_data_wrapper "\
  612. " WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
  613. #define Query_for_list_of_servers \
  614. " SELECT pg_catalog.quote_ident(srvname) "\
  615. " FROM pg_catalog.pg_foreign_server "\
  616. " WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
  617. #define Query_for_list_of_user_mappings \
  618. " SELECT pg_catalog.quote_ident(usename) "\
  619. " FROM pg_catalog.pg_user_mappings "\
  620. " WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
  621. #define Query_for_list_of_access_methods \
  622. " SELECT pg_catalog.quote_ident(amname) "\
  623. " FROM pg_catalog.pg_am "\
  624. " WHERE substring(pg_catalog.quote_ident(amname),1,%d)='%s'"
  625. /* the silly-looking length condition is just to eat up the current word */
  626. #define Query_for_list_of_arguments \
  627. "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
  628. " FROM pg_catalog.pg_proc "\
  629. " WHERE (%d = pg_catalog.length('%s'))"\
  630. " AND (pg_catalog.quote_ident(proname)='%s'"\
  631. " OR '\"' || proname || '\"'='%s') "\
  632. " AND (pg_catalog.pg_function_is_visible(pg_proc.oid))"
  633. /* the silly-looking length condition is just to eat up the current word */
  634. #define Query_for_list_of_arguments_with_schema \
  635. "SELECT pg_catalog.oidvectortypes(proargtypes)||')' "\
  636. " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "\
  637. " WHERE (%d = pg_catalog.length('%s'))"\
  638. " AND n.oid = p.pronamespace "\
  639. " AND (pg_catalog.quote_ident(proname)='%s' "\
  640. " OR '\"' || proname || '\"' ='%s') "\
  641. " AND (pg_catalog.quote_ident(nspname)='%s' "\
  642. " OR '\"' || nspname || '\"' ='%s') "
  643. #define Query_for_list_of_extensions \
  644. " SELECT pg_catalog.quote_ident(extname) "\
  645. " FROM pg_catalog.pg_extension "\
  646. " WHERE substring(pg_catalog.quote_ident(extname),1,%d)='%s'"
  647. #define Query_for_list_of_available_extensions \
  648. " SELECT pg_catalog.quote_ident(name) "\
  649. " FROM pg_catalog.pg_available_extensions "\
  650. " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s' AND installed_version IS NULL"
  651. #define Query_for_list_of_prepared_statements \
  652. " SELECT pg_catalog.quote_ident(name) "\
  653. " FROM pg_catalog.pg_prepared_statements "\
  654. " WHERE substring(pg_catalog.quote_ident(name),1,%d)='%s'"
  655. #define Query_for_list_of_event_triggers \
  656. " SELECT pg_catalog.quote_ident(evtname) "\
  657. " FROM pg_catalog.pg_event_trigger "\
  658. " WHERE substring(pg_catalog.quote_ident(evtname),1,%d)='%s'"
  659. /*
  660. * This is a list of all "things" in Pgsql, which can show up after CREATE or
  661. * DROP; and there is also a query to get a list of them.
  662. */
  663. typedef struct
  664. {
  665. const char *name;
  666. const char *query; /* simple query, or NULL */
  667. const SchemaQuery *squery; /* schema query, or NULL */
  668. const bits32 flags; /* visibility flags, see below */
  669. } pgsql_thing_t;
  670. #define THING_NO_CREATE (1 << 0) /* should not show up after CREATE */
  671. #define THING_NO_DROP (1 << 1) /* should not show up after DROP */
  672. #define THING_NO_SHOW (THING_NO_CREATE | THING_NO_DROP)
  673. static const pgsql_thing_t words_after_create[] = {
  674. {"AGGREGATE", NULL, &Query_for_list_of_aggregates},
  675. {"CAST", NULL, NULL}, /* Casts have complex structures for names, so
  676. * skip it */
  677. {"COLLATION", "SELECT pg_catalog.quote_ident(collname) FROM pg_catalog.pg_collation WHERE collencoding IN (-1, pg_catalog.pg_char_to_encoding(pg_catalog.getdatabaseencoding())) AND substring(pg_catalog.quote_ident(collname),1,%d)='%s'"},
  678. /*
  679. * CREATE CONSTRAINT TRIGGER is not supported here because it is designed
  680. * to be used only by pg_dump.
  681. */
  682. {"CONFIGURATION", Query_for_list_of_ts_configurations, NULL, THING_NO_SHOW},
  683. {"CONVERSION", "SELECT pg_catalog.quote_ident(conname) FROM pg_catalog.pg_conversion WHERE substring(pg_catalog.quote_ident(conname),1,%d)='%s'"},
  684. {"DATABASE", Query_for_list_of_databases},
  685. {"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, THING_NO_SHOW},
  686. {"DOMAIN", NULL, &Query_for_list_of_domains},
  687. {"EVENT TRIGGER", NULL, NULL},
  688. {"EXTENSION", Query_for_list_of_extensions},
  689. {"FOREIGN DATA WRAPPER", NULL, NULL},
  690. {"FOREIGN TABLE", NULL, NULL},
  691. {"FUNCTION", NULL, &Query_for_list_of_functions},
  692. {"GROUP", Query_for_list_of_roles},
  693. {"LANGUAGE", Query_for_list_of_languages},
  694. {"INDEX", NULL, &Query_for_list_of_indexes},
  695. {"MATERIALIZED VIEW", NULL, NULL},
  696. {"OPERATOR", NULL, NULL}, /* Querying for this is probably not such a
  697. * good idea. */
  698. {"OWNED", NULL, NULL, THING_NO_CREATE}, /* for DROP OWNED BY ... */
  699. {"PARSER", Query_for_list_of_ts_parsers, NULL, THING_NO_SHOW},
  700. {"ROLE", Query_for_list_of_roles},
  701. {"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
  702. {"SCHEMA", Query_for_list_of_schemas},
  703. {"SEQUENCE", NULL, &Query_for_list_of_sequences},
  704. {"SERVER", Query_for_list_of_servers},
  705. {"TABLE", NULL, &Query_for_list_of_tables},
  706. {"TABLESPACE", Query_for_list_of_tablespaces},
  707. {"TEMP", NULL, NULL, THING_NO_DROP}, /* for CREATE TEMP TABLE ... */
  708. {"TEMPLATE", Query_for_list_of_ts_templates, NULL, THING_NO_SHOW},
  709. {"TEXT SEARCH", NULL, NULL},
  710. {"TRIGGER", "SELECT pg_catalog.quote_ident(tgname) FROM pg_catalog.pg_trigger WHERE substring(pg_catalog.quote_ident(tgname),1,%d)='%s' AND NOT tgisinternal"},
  711. {"TYPE", NULL, &Query_for_list_of_datatypes},
  712. {"UNIQUE", NULL, NULL, THING_NO_DROP}, /* for CREATE UNIQUE INDEX ... */
  713. {"UNLOGGED", NULL, NULL, THING_NO_DROP}, /* for CREATE UNLOGGED TABLE
  714. * ... */
  715. {"USER", Query_for_list_of_roles},
  716. {"USER MAPPING FOR", NULL, NULL},
  717. {"VIEW", NULL, &Query_for_list_of_views},
  718. {NULL} /* end of list */
  719. };
  720. /* Forward declaration of functions */
  721. static char **psql_completion(const char *text, int start, int end);
  722. static char *create_command_generator(const char *text, int state);
  723. static char *drop_command_generator(const char *text, int state);
  724. static char *complete_from_query(const char *text, int state);
  725. static char *complete_from_schema_query(const char *text, int state);
  726. static char *_complete_from_query(int is_schema_query,
  727. const char *text, int state);
  728. static char *complete_from_list(const char *text, int state);
  729. static char *complete_from_const(const char *text, int state);
  730. static char **complete_from_variables(const char *text,
  731. const char *prefix, const char *suffix);
  732. static char *complete_from_files(const char *text, int state);
  733. static char *pg_strdup_keyword_case(const char *s, const char *ref);
  734. static PGresult *exec_query(const char *query);
  735. static void get_previous_words(int point, char **previous_words, int nwords);
  736. #ifdef NOT_USED
  737. static char *quote_file_name(char *text, int match_type, char *quote_pointer);
  738. static char *dequote_file_name(char *text, char quote_char);
  739. #endif
  740. /*
  741. * Initialize the readline library for our purposes.
  742. */
  743. void
  744. initialize_readline(void)
  745. {
  746. rl_readline_name = (char *) pset.progname;
  747. rl_attempted_completion_function = psql_completion;
  748. rl_basic_word_break_characters = WORD_BREAKS;
  749. completion_max_records = 1000;
  750. /*
  751. * There is a variable rl_completion_query_items for this but apparently
  752. * it's not defined everywhere.
  753. */
  754. }
  755. /*
  756. * The completion function.
  757. *
  758. * According to readline spec this gets passed the text entered so far and its
  759. * start and end positions in the readline buffer. The return value is some
  760. * partially obscure list format that can be generated by readline's
  761. * completion_matches() function, so we don't have to worry about it.
  762. */
  763. static char **
  764. psql_completion(const char *text, int start, int end)
  765. {
  766. /* This is the variable we'll return. */
  767. char **matches = NULL;
  768. /* This array will contain some scannage of the input line. */
  769. char *previous_words[6];
  770. /* For compactness, we use these macros to reference previous_words[]. */
  771. #define prev_wd (previous_words[0])
  772. #define prev2_wd (previous_words[1])
  773. #define prev3_wd (previous_words[2])
  774. #define prev4_wd (previous_words[3])
  775. #define prev5_wd (previous_words[4])
  776. #define prev6_wd (previous_words[5])
  777. static const char *const sql_commands[] = {
  778. "ABORT", "ALTER", "ANALYZE", "BEGIN", "CHECKPOINT", "CLOSE", "CLUSTER",
  779. "COMMENT", "COMMIT", "COPY", "CREATE", "DEALLOCATE", "DECLARE",
  780. "DELETE FROM", "DISCARD", "DO", "DROP", "END", "EXECUTE", "EXPLAIN",
  781. "FETCH", "GRANT", "IMPORT", "INSERT", "LISTEN", "LOAD", "LOCK",
  782. "MOVE", "NOTIFY", "PREPARE",
  783. "REASSIGN", "REFRESH", "REINDEX", "RELEASE", "RESET", "REVOKE", "ROLLBACK",
  784. "SAVEPOINT", "SECURITY LABEL", "SELECT", "SET", "SHOW", "START",
  785. "TABLE", "TRUNCATE", "UNLISTEN", "UPDATE", "VACUUM", "VALUES", "WITH",
  786. NULL
  787. };
  788. static const char *const backslash_commands[] = {
  789. "\\a", "\\connect", "\\conninfo", "\\C", "\\cd", "\\copy", "\\copyright",
  790. "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\det", "\\deu", "\\dew", "\\df",
  791. "\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
  792. "\\dn", "\\do", "\\dp", "\\drds", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du", "\\dx",
  793. "\\e", "\\echo", "\\ef", "\\encoding",
  794. "\\f", "\\g", "\\gset", "\\h", "\\help", "\\H", "\\i", "\\ir", "\\l",
  795. "\\lo_import", "\\lo_export", "\\lo_list", "\\lo_unlink",
  796. "\\o", "\\p", "\\password", "\\prompt", "\\pset", "\\q", "\\qecho", "\\r",
  797. "\\set", "\\sf", "\\t", "\\T",
  798. "\\timing", "\\unset", "\\x", "\\w", "\\watch", "\\z", "\\!", NULL
  799. };
  800. (void) end; /* not used */
  801. #ifdef HAVE_RL_COMPLETION_APPEND_CHARACTER
  802. rl_completion_append_character = ' ';
  803. #endif
  804. /* Clear a few things. */
  805. completion_charp = NULL;
  806. completion_charpp = NULL;
  807. completion_info_charp = NULL;
  808. completion_info_charp2 = NULL;
  809. /*
  810. * Scan the input line before our current position for the last few words.
  811. * According to those we'll make some smart decisions on what the user is
  812. * probably intending to type.
  813. */
  814. get_previous_words(start, previous_words, lengthof(previous_words));
  815. /* If a backslash command was started, continue */
  816. if (text[0] == '\\')
  817. COMPLETE_WITH_LIST_CS(backslash_commands);
  818. /* Variable interpolation */
  819. else if (text[0] == ':' && text[1] != ':')
  820. {
  821. if (text[1] == '\'')
  822. matches = complete_from_variables(text, ":'", "'");
  823. else if (text[1] == '"')
  824. matches = complete_from_variables(text, ":\"", "\"");
  825. else
  826. matches = complete_from_variables(text, ":", "");
  827. }
  828. /* If no previous word, suggest one of the basic sql commands */
  829. else if (prev_wd[0] == '\0')
  830. COMPLETE_WITH_LIST(sql_commands);
  831. /* CREATE */
  832. /* complete with something you can create */
  833. else if (pg_strcasecmp(prev_wd, "CREATE") == 0)
  834. matches = completion_matches(text, create_command_generator);
  835. /* DROP, but not DROP embedded in other commands */
  836. /* complete with something you can drop */
  837. else if (pg_strcasecmp(prev_wd, "DROP") == 0 &&
  838. prev2_wd[0] == '\0')
  839. matches = completion_matches(text, drop_command_generator);
  840. /* ALTER */
  841. /*
  842. * complete with what you can alter (TABLE, GROUP, USER, ...) unless we're
  843. * in ALTER TABLE sth ALTER
  844. */
  845. else if (pg_strcasecmp(prev_wd, "ALTER") == 0 &&
  846. pg_strcasecmp(prev3_wd, "TABLE") != 0)
  847. {
  848. static const char *const list_ALTER[] =
  849. {"AGGREGATE", "COLLATION", "CONVERSION", "DATABASE", "DEFAULT PRIVILEGES", "DOMAIN",
  850. "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", "FUNCTION",
  851. "GROUP", "INDEX", "LANGUAGE", "LARGE OBJECT", "MATERIALIZED VIEW", "OPERATOR",
  852. "ROLE", "RULE", "SCHEMA", "SERVER", "SEQUENCE", "SYSTEM SET", "TABLE",
  853. "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE",
  854. "USER", "USER MAPPING FOR", "VIEW", NULL};
  855. COMPLETE_WITH_LIST(list_ALTER);
  856. }
  857. /* ALTER AGGREGATE,FUNCTION <name> */
  858. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  859. (pg_strcasecmp(prev2_wd, "AGGREGATE") == 0 ||
  860. pg_strcasecmp(prev2_wd, "FUNCTION") == 0))
  861. COMPLETE_WITH_CONST("(");
  862. /* ALTER AGGREGATE,FUNCTION <name> (...) */
  863. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  864. (pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 ||
  865. pg_strcasecmp(prev3_wd, "FUNCTION") == 0))
  866. {
  867. if (prev_wd[strlen(prev_wd) - 1] == ')')
  868. {
  869. static const char *const list_ALTERAGG[] =
  870. {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  871. COMPLETE_WITH_LIST(list_ALTERAGG);
  872. }
  873. else
  874. COMPLETE_WITH_FUNCTION_ARG(prev2_wd);
  875. }
  876. /* ALTER SCHEMA <name> */
  877. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  878. pg_strcasecmp(prev2_wd, "SCHEMA") == 0)
  879. {
  880. static const char *const list_ALTERGEN[] =
  881. {"OWNER TO", "RENAME TO", NULL};
  882. COMPLETE_WITH_LIST(list_ALTERGEN);
  883. }
  884. /* ALTER COLLATION <name> */
  885. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  886. pg_strcasecmp(prev2_wd, "COLLATION") == 0)
  887. {
  888. static const char *const list_ALTERGEN[] =
  889. {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  890. COMPLETE_WITH_LIST(list_ALTERGEN);
  891. }
  892. /* ALTER CONVERSION <name> */
  893. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  894. pg_strcasecmp(prev2_wd, "CONVERSION") == 0)
  895. {
  896. static const char *const list_ALTERGEN[] =
  897. {"OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  898. COMPLETE_WITH_LIST(list_ALTERGEN);
  899. }
  900. /* ALTER DATABASE <name> */
  901. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  902. pg_strcasecmp(prev2_wd, "DATABASE") == 0)
  903. {
  904. static const char *const list_ALTERDATABASE[] =
  905. {"RESET", "SET", "OWNER TO", "RENAME TO", "IS_TEMPLATE",
  906. "ALLOW_CONNECTIONS", "CONNECTION LIMIT", NULL};
  907. COMPLETE_WITH_LIST(list_ALTERDATABASE);
  908. }
  909. /* ALTER EVENT TRIGGER */
  910. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  911. pg_strcasecmp(prev2_wd, "EVENT") == 0 &&
  912. pg_strcasecmp(prev_wd, "TRIGGER") == 0)
  913. {
  914. COMPLETE_WITH_QUERY(Query_for_list_of_event_triggers);
  915. }
  916. /* ALTER EVENT TRIGGER <name> */
  917. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  918. pg_strcasecmp(prev3_wd, "EVENT") == 0 &&
  919. pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
  920. {
  921. static const char *const list_ALTER_EVENT_TRIGGER[] =
  922. {"DISABLE", "ENABLE", "OWNER TO", "RENAME TO", NULL};
  923. COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER);
  924. }
  925. /* ALTER EVENT TRIGGER <name> ENABLE */
  926. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  927. pg_strcasecmp(prev4_wd, "EVENT") == 0 &&
  928. pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
  929. pg_strcasecmp(prev_wd, "ENABLE") == 0)
  930. {
  931. static const char *const list_ALTER_EVENT_TRIGGER_ENABLE[] =
  932. {"REPLICA", "ALWAYS", NULL};
  933. COMPLETE_WITH_LIST(list_ALTER_EVENT_TRIGGER_ENABLE);
  934. }
  935. /* ALTER EXTENSION <name> */
  936. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  937. pg_strcasecmp(prev2_wd, "EXTENSION") == 0)
  938. {
  939. static const char *const list_ALTEREXTENSION[] =
  940. {"ADD", "DROP", "UPDATE", "SET SCHEMA", NULL};
  941. COMPLETE_WITH_LIST(list_ALTEREXTENSION);
  942. }
  943. /* ALTER FOREIGN */
  944. else if (pg_strcasecmp(prev2_wd, "ALTER") == 0 &&
  945. pg_strcasecmp(prev_wd, "FOREIGN") == 0)
  946. {
  947. static const char *const list_ALTER_FOREIGN[] =
  948. {"DATA WRAPPER", "TABLE", NULL};
  949. COMPLETE_WITH_LIST(list_ALTER_FOREIGN);
  950. }
  951. /* ALTER FOREIGN DATA WRAPPER <name> */
  952. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  953. pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
  954. pg_strcasecmp(prev3_wd, "DATA") == 0 &&
  955. pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
  956. {
  957. static const char *const list_ALTER_FDW[] =
  958. {"HANDLER", "VALIDATOR", "OPTIONS", "OWNER TO", NULL};
  959. COMPLETE_WITH_LIST(list_ALTER_FDW);
  960. }
  961. /* ALTER FOREIGN TABLE <name> */
  962. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  963. pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
  964. pg_strcasecmp(prev2_wd, "TABLE") == 0)
  965. {
  966. static const char *const list_ALTER_FOREIGN_TABLE[] =
  967. {"ALTER", "DROP", "RENAME", "OWNER TO", "SET SCHEMA", NULL};
  968. COMPLETE_WITH_LIST(list_ALTER_FOREIGN_TABLE);
  969. }
  970. /* ALTER INDEX <name> */
  971. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  972. pg_strcasecmp(prev2_wd, "INDEX") == 0)
  973. {
  974. static const char *const list_ALTERINDEX[] =
  975. {"OWNER TO", "RENAME TO", "SET", "RESET", NULL};
  976. COMPLETE_WITH_LIST(list_ALTERINDEX);
  977. }
  978. /* ALTER INDEX <name> SET */
  979. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  980. pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
  981. pg_strcasecmp(prev_wd, "SET") == 0)
  982. {
  983. static const char *const list_ALTERINDEXSET[] =
  984. {"(", "TABLESPACE", NULL};
  985. COMPLETE_WITH_LIST(list_ALTERINDEXSET);
  986. }
  987. /* ALTER INDEX <name> RESET */
  988. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  989. pg_strcasecmp(prev3_wd, "INDEX") == 0 &&
  990. pg_strcasecmp(prev_wd, "RESET") == 0)
  991. COMPLETE_WITH_CONST("(");
  992. /* ALTER INDEX <foo> SET|RESET ( */
  993. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  994. pg_strcasecmp(prev4_wd, "INDEX") == 0 &&
  995. (pg_strcasecmp(prev2_wd, "SET") == 0 ||
  996. pg_strcasecmp(prev2_wd, "RESET") == 0) &&
  997. pg_strcasecmp(prev_wd, "(") == 0)
  998. {
  999. static const char *const list_INDEXOPTIONS[] =
  1000. {"fillfactor", "fastupdate", NULL};
  1001. COMPLETE_WITH_LIST(list_INDEXOPTIONS);
  1002. }
  1003. /* ALTER LANGUAGE <name> */
  1004. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1005. pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
  1006. {
  1007. static const char *const list_ALTERLANGUAGE[] =
  1008. {"OWNER TO", "RENAME TO", NULL};
  1009. COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
  1010. }
  1011. /* ALTER LARGE OBJECT <oid> */
  1012. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1013. pg_strcasecmp(prev3_wd, "LARGE") == 0 &&
  1014. pg_strcasecmp(prev2_wd, "OBJECT") == 0)
  1015. {
  1016. static const char *const list_ALTERLARGEOBJECT[] =
  1017. {"OWNER TO", NULL};
  1018. COMPLETE_WITH_LIST(list_ALTERLARGEOBJECT);
  1019. }
  1020. /* ALTER MATERIALIZED VIEW */
  1021. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1022. pg_strcasecmp(prev2_wd, "MATERIALIZED") == 0 &&
  1023. pg_strcasecmp(prev_wd, "VIEW") == 0)
  1024. {
  1025. COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_matviews, NULL);
  1026. }
  1027. /* ALTER USER,ROLE <name> */
  1028. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1029. !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
  1030. (pg_strcasecmp(prev2_wd, "USER") == 0 ||
  1031. pg_strcasecmp(prev2_wd, "ROLE") == 0))
  1032. {
  1033. static const char *const list_ALTERUSER[] =
  1034. {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
  1035. "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
  1036. "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
  1037. "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
  1038. "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", "WITH", NULL};
  1039. COMPLETE_WITH_LIST(list_ALTERUSER);
  1040. }
  1041. /* ALTER USER,ROLE <name> WITH */
  1042. else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1043. (pg_strcasecmp(prev3_wd, "USER") == 0 ||
  1044. pg_strcasecmp(prev3_wd, "ROLE") == 0) &&
  1045. pg_strcasecmp(prev_wd, "WITH") == 0))
  1046. {
  1047. /* Similar to the above, but don't complete "WITH" again. */
  1048. static const char *const list_ALTERUSER_WITH[] =
  1049. {"CONNECTION LIMIT", "CREATEDB", "CREATEROLE", "CREATEUSER",
  1050. "ENCRYPTED", "INHERIT", "LOGIN", "NOCREATEDB", "NOCREATEROLE",
  1051. "NOCREATEUSER", "NOINHERIT", "NOLOGIN", "NOREPLICATION",
  1052. "NOSUPERUSER", "RENAME TO", "REPLICATION", "RESET", "SET",
  1053. "SUPERUSER", "UNENCRYPTED", "VALID UNTIL", NULL};
  1054. COMPLETE_WITH_LIST(list_ALTERUSER_WITH);
  1055. }
  1056. /* complete ALTER USER,ROLE <name> ENCRYPTED,UNENCRYPTED with PASSWORD */
  1057. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1058. (pg_strcasecmp(prev3_wd, "ROLE") == 0 || pg_strcasecmp(prev3_wd, "USER") == 0) &&
  1059. (pg_strcasecmp(prev_wd, "ENCRYPTED") == 0 || pg_strcasecmp(prev_wd, "UNENCRYPTED") == 0))
  1060. {
  1061. COMPLETE_WITH_CONST("PASSWORD");
  1062. }
  1063. /* ALTER DEFAULT PRIVILEGES */
  1064. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1065. pg_strcasecmp(prev2_wd, "DEFAULT") == 0 &&
  1066. pg_strcasecmp(prev_wd, "PRIVILEGES") == 0)
  1067. {
  1068. static const char *const list_ALTER_DEFAULT_PRIVILEGES[] =
  1069. {"FOR ROLE", "FOR USER", "IN SCHEMA", NULL};
  1070. COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES);
  1071. }
  1072. /* ALTER DEFAULT PRIVILEGES FOR */
  1073. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1074. pg_strcasecmp(prev3_wd, "DEFAULT") == 0 &&
  1075. pg_strcasecmp(prev2_wd, "PRIVILEGES") == 0 &&
  1076. pg_strcasecmp(prev_wd, "FOR") == 0)
  1077. {
  1078. static const char *const list_ALTER_DEFAULT_PRIVILEGES_FOR[] =
  1079. {"ROLE", "USER", NULL};
  1080. COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_FOR);
  1081. }
  1082. /* ALTER DEFAULT PRIVILEGES { FOR ROLE ... | IN SCHEMA ... } */
  1083. else if (pg_strcasecmp(prev5_wd, "DEFAULT") == 0 &&
  1084. pg_strcasecmp(prev4_wd, "PRIVILEGES") == 0 &&
  1085. (pg_strcasecmp(prev3_wd, "FOR") == 0 ||
  1086. pg_strcasecmp(prev3_wd, "IN") == 0))
  1087. {
  1088. static const char *const list_ALTER_DEFAULT_PRIVILEGES_REST[] =
  1089. {"GRANT", "REVOKE", NULL};
  1090. COMPLETE_WITH_LIST(list_ALTER_DEFAULT_PRIVILEGES_REST);
  1091. }
  1092. /* ALTER DOMAIN <name> */
  1093. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1094. pg_strcasecmp(prev2_wd, "DOMAIN") == 0)
  1095. {
  1096. static const char *const list_ALTERDOMAIN[] =
  1097. {"ADD", "DROP", "OWNER TO", "RENAME", "SET", "VALIDATE CONSTRAINT", NULL};
  1098. COMPLETE_WITH_LIST(list_ALTERDOMAIN);
  1099. }
  1100. /* ALTER DOMAIN <sth> DROP */
  1101. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1102. pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
  1103. pg_strcasecmp(prev_wd, "DROP") == 0)
  1104. {
  1105. static const char *const list_ALTERDOMAIN2[] =
  1106. {"CONSTRAINT", "DEFAULT", "NOT NULL", NULL};
  1107. COMPLETE_WITH_LIST(list_ALTERDOMAIN2);
  1108. }
  1109. /* ALTER DOMAIN <sth> DROP|RENAME|VALIDATE CONSTRAINT */
  1110. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1111. pg_strcasecmp(prev4_wd, "DOMAIN") == 0 &&
  1112. (pg_strcasecmp(prev2_wd, "DROP") == 0 ||
  1113. pg_strcasecmp(prev2_wd, "RENAME") == 0 ||
  1114. pg_strcasecmp(prev2_wd, "VALIDATE") == 0) &&
  1115. pg_strcasecmp(prev_wd, "CONSTRAINT") == 0)
  1116. {
  1117. completion_info_charp = prev3_wd;
  1118. COMPLETE_WITH_QUERY(Query_for_constraint_of_type);
  1119. }
  1120. /* ALTER DOMAIN <sth> RENAME */
  1121. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1122. pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
  1123. pg_strcasecmp(prev_wd, "RENAME") == 0)
  1124. {
  1125. static const char *const list_ALTERDOMAIN[] =
  1126. {"CONSTRAINT", "TO", NULL};
  1127. COMPLETE_WITH_LIST(list_ALTERDOMAIN);
  1128. }
  1129. /* ALTER DOMAIN <sth> RENAME CONSTRAINT <sth> */
  1130. else if (pg_strcasecmp(prev5_wd, "DOMAIN") == 0 &&
  1131. pg_strcasecmp(prev3_wd, "RENAME") == 0 &&
  1132. pg_strcasecmp(prev2_wd, "CONSTRAINT") == 0)
  1133. COMPLETE_WITH_CONST("TO");
  1134. /* ALTER DOMAIN <sth> SET */
  1135. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1136. pg_strcasecmp(prev3_wd, "DOMAIN") == 0 &&
  1137. pg_strcasecmp(prev_wd, "SET") == 0)
  1138. {
  1139. static const char *const list_ALTERDOMAIN3[] =
  1140. {"DEFAULT", "NOT NULL", "SCHEMA", NULL};
  1141. COMPLETE_WITH_LIST(list_ALTERDOMAIN3);
  1142. }
  1143. /* ALTER SEQUENCE <name> */
  1144. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1145. pg_strcasecmp(prev2_wd, "SEQUENCE") == 0)
  1146. {
  1147. static const char *const list_ALTERSEQUENCE[] =
  1148. {"INCREMENT", "MINVALUE", "MAXVALUE", "RESTART", "NO", "CACHE", "CYCLE",
  1149. "SET SCHEMA", "OWNED BY", "OWNER TO", "RENAME TO", NULL};
  1150. COMPLETE_WITH_LIST(list_ALTERSEQUENCE);
  1151. }
  1152. /* ALTER SEQUENCE <name> NO */
  1153. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1154. pg_strcasecmp(prev3_wd, "SEQUENCE") == 0 &&
  1155. pg_strcasecmp(prev_wd, "NO") == 0)
  1156. {
  1157. static const char *const list_ALTERSEQUENCE2[] =
  1158. {"MINVALUE", "MAXVALUE", "CYCLE", NULL};
  1159. COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
  1160. }
  1161. /* ALTER SERVER <name> */
  1162. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1163. pg_strcasecmp(prev2_wd, "SERVER") == 0)
  1164. {
  1165. static const char *const list_ALTER_SERVER[] =
  1166. {"VERSION", "OPTIONS", "OWNER TO", NULL};
  1167. COMPLETE_WITH_LIST(list_ALTER_SERVER);
  1168. }
  1169. /* ALTER SYSTEM SET <name> */
  1170. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1171. pg_strcasecmp(prev2_wd, "SYSTEM") == 0 &&
  1172. pg_strcasecmp(prev_wd, "SET") == 0)
  1173. COMPLETE_WITH_QUERY(Query_for_list_of_alter_system_set_vars);
  1174. /* ALTER VIEW <name> */
  1175. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1176. pg_strcasecmp(prev2_wd, "VIEW") == 0)
  1177. {
  1178. static const char *const list_ALTERVIEW[] =
  1179. {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  1180. COMPLETE_WITH_LIST(list_ALTERVIEW);
  1181. }
  1182. /* ALTER MATERIALIZED VIEW <name> */
  1183. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1184. pg_strcasecmp(prev3_wd, "MATERIALIZED") == 0 &&
  1185. pg_strcasecmp(prev2_wd, "VIEW") == 0)
  1186. {
  1187. static const char *const list_ALTERMATVIEW[] =
  1188. {"ALTER COLUMN", "OWNER TO", "RENAME TO", "SET SCHEMA", NULL};
  1189. COMPLETE_WITH_LIST(list_ALTERMATVIEW);
  1190. }
  1191. /* ALTER RULE <name>, add ON */
  1192. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1193. pg_strcasecmp(prev2_wd, "RULE") == 0)
  1194. COMPLETE_WITH_CONST("ON");
  1195. /* If we have ALTER RULE <name> ON, then add the correct tablename */
  1196. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1197. pg_strcasecmp(prev3_wd, "RULE") == 0 &&
  1198. pg_strcasecmp(prev_wd, "ON") == 0)
  1199. {
  1200. completion_info_charp = prev2_wd;
  1201. COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_rule);
  1202. }
  1203. /* ALTER RULE <name> ON <name> */
  1204. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1205. pg_strcasecmp(prev4_wd, "RULE") == 0)
  1206. COMPLETE_WITH_CONST("RENAME TO");
  1207. /* ALTER TRIGGER <name>, add ON */
  1208. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1209. pg_strcasecmp(prev2_wd, "TRIGGER") == 0)
  1210. COMPLETE_WITH_CONST("ON");
  1211. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1212. pg_strcasecmp(prev3_wd, "TRIGGER") == 0)
  1213. {
  1214. completion_info_charp = prev2_wd;
  1215. COMPLETE_WITH_QUERY(Query_for_list_of_tables_for_trigger);
  1216. }
  1217. /*
  1218. * If we have ALTER TRIGGER <sth> ON, then add the correct tablename
  1219. */
  1220. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1221. pg_strcasecmp(prev3_wd, "TRIGGER") == 0 &&
  1222. pg_strcasecmp(prev_wd, "ON") == 0)
  1223. COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
  1224. /* ALTER TRIGGER <name> ON <name> */
  1225. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1226. pg_strcasecmp(prev4_wd, "TRIGGER") == 0 &&
  1227. pg_strcasecmp(prev2_wd, "ON") == 0)
  1228. COMPLETE_WITH_CONST("RENAME TO");
  1229. /*
  1230. * If we detect ALTER TABLE <name>, suggest sub commands
  1231. */
  1232. else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  1233. pg_strcasecmp(prev2_wd, "TABLE") == 0)
  1234. {
  1235. static const char *const list_ALTER2[] =
  1236. {"ADD", "ALTER", "CLUSTER ON", "DISABLE", "DROP", "ENABLE", "INHERIT",
  1237. "NO INHERIT", "RENAME", "RESET", "OWNER TO", "SET",
  1238. "VALIDATE CONSTRAINT", "REPLICA IDENTITY", NULL};
  1239. COMPLETE_WITH_LIST(list_ALTER2);
  1240. }
  1241. /* ALTER TABLE xxx ENABLE */
  1242. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1243. pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  1244. pg_strcasecmp(prev_wd, "ENABLE") == 0)
  1245. {
  1246. static const char *const list_ALTERENABLE[] =
  1247. {"ALWAYS", "REPLICA", "RULE", "TRIGGER", NULL};
  1248. COMPLETE_WITH_LIST(list_ALTERENABLE);
  1249. }
  1250. else if (pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
  1251. pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
  1252. (pg_strcasecmp(prev_wd, "REPLICA") == 0 ||
  1253. pg_strcasecmp(prev_wd, "ALWAYS") == 0))
  1254. {
  1255. static const char *const list_ALTERENABLE2[] =
  1256. {"RULE", "TRIGGER", NULL};
  1257. COMPLETE_WITH_LIST(list_ALTERENABLE2);
  1258. }
  1259. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1260. pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
  1261. pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
  1262. pg_strcasecmp(prev_wd, "RULE") == 0)
  1263. {
  1264. completion_info_charp = prev3_wd;
  1265. COMPLETE_WITH_QUERY(Query_for_rule_of_table);
  1266. }
  1267. else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
  1268. pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
  1269. pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
  1270. pg_strcasecmp(prev_wd, "RULE") == 0)
  1271. {
  1272. completion_info_charp = prev4_wd;
  1273. COMPLETE_WITH_QUERY(Query_for_rule_of_table);
  1274. }
  1275. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1276. pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
  1277. pg_strcasecmp(prev2_wd, "ENABLE") == 0 &&
  1278. pg_strcasecmp(prev_wd, "TRIGGER") == 0)
  1279. {
  1280. completion_info_charp = prev3_wd;
  1281. COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
  1282. }
  1283. else if (pg_strcasecmp(prev6_wd, "ALTER") == 0 &&
  1284. pg_strcasecmp(prev5_wd, "TABLE") == 0 &&
  1285. pg_strcasecmp(prev3_wd, "ENABLE") == 0 &&
  1286. pg_strcasecmp(prev_wd, "TRIGGER") == 0)
  1287. {
  1288. completion_info_charp = prev4_wd;
  1289. COMPLETE_WITH_QUERY(Query_for_trigger_of_table);
  1290. }
  1291. /* ALTER TABLE xxx INHERIT */
  1292. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1293. pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  1294. pg_strcasecmp(prev_wd, "INHERIT") == 0)
  1295. {
  1296. COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
  1297. }
  1298. /* ALTER TABLE xxx NO INHERIT */
  1299. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1300. pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
  1301. pg_strcasecmp(prev2_wd, "NO") == 0 &&
  1302. pg_strcasecmp(prev_wd, "INHERIT") == 0)
  1303. {
  1304. COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, "");
  1305. }
  1306. /* ALTER TABLE xxx DISABLE */
  1307. else if (pg_strcasecmp(prev4_wd, "ALTER") == 0 &&
  1308. pg_strcasecmp(prev3_wd, "TABLE") == 0 &&
  1309. pg_strcasecmp(prev_wd, "DISABLE") == 0)
  1310. {
  1311. static const char *const list_ALTERDISABLE[] =
  1312. {"RULE", "TRIGGER", NULL};
  1313. COMPLETE_WITH_LIST(list_ALTERDISABLE);
  1314. }
  1315. else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
  1316. pg_strcasecmp(prev4_wd, "TABLE") == 0 &&
  1317. pg_strcasecmp(prev2_wd, "DISABLE") == 0 &&
  1318. pg_strcasecmp(prev_wd, "RULE") == 0)
  1319. {
  1320. completion_i

Large files files are truncated, but you can click here to view the full file