3
3
*
4
4
* Copyright (c) 2000-2006, PostgreSQL Global Development Group
5
5
*
6
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.149 2006/03/05 15:58:52 momjian Exp $
6
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.150 2006/04/02 09:02:41 alvherre Exp $
7
7
*/
8
8
9
9
/*----------------------------------------------------------------------
@@ -465,6 +465,7 @@ static const pgsql_thing_t words_after_create[] = {
465
465
/* Forward declaration of functions */
466
466
static char * * psql_completion (char * text ,int start ,int end );
467
467
static char * create_command_generator (const char * text ,int state );
468
+ static char * drop_command_generator (const char * text ,int state );
468
469
static char * complete_from_query (const char * text ,int state );
469
470
static char * complete_from_schema_query (const char * text ,int state );
470
471
static char * _complete_from_query (int is_schema_query ,
@@ -521,11 +522,13 @@ psql_completion(char *text, int start, int end)
521
522
* prev5_wd ;
522
523
523
524
static const char * const sql_commands []= {
524
- "ABORT" ,"ALTER" ,"ANALYZE" ,"BEGIN" ,"CHECKPOINT" ,"CLOSE" ,"CLUSTER" ,"COMMENT" ,
525
- "COMMIT" ,"COPY" ,"CREATE" ,"DEALLOCATE" ,"DECLARE" ,"DELETE FROM" ,"DROP" ,"END" ,"EXECUTE" ,
526
- "EXPLAIN" ,"FETCH" ,"GRANT" ,"INSERT" ,"LISTEN" ,"LOAD" ,"LOCK" ,"MOVE" ,"NOTIFY" ,
527
- "PREPARE" ,"REINDEX" ,"RELEASE" ,"RESET" ,"REVOKE" ,"ROLLBACK" ,"SAVEPOINT" ,
528
- "SELECT" ,"SET" ,"SHOW" ,"START" ,"TRUNCATE" ,"UNLISTEN" ,"UPDATE" ,"VACUUM" ,NULL
525
+ "ABORT" ,"ALTER" ,"ANALYZE" ,"BEGIN" ,"CHECKPOINT" ,"CLOSE" ,"CLUSTER" ,
526
+ "COMMENT" ,"COMMIT" ,"COPY" ,"CREATE" ,"DEALLOCATE" ,"DECLARE" ,
527
+ "DELETE FROM" ,"DROP" ,"END" ,"EXECUTE" ,"EXPLAIN" ,"FETCH" ,"GRANT" ,
528
+ "INSERT" ,"LISTEN" ,"LOAD" ,"LOCK" ,"MOVE" ,"NOTIFY" ,"PREPARE" ,
529
+ "REASSIGN" ,"REINDEX" ,"RELEASE" ,"RESET" ,"REVOKE" ,"ROLLBACK" ,
530
+ "SAVEPOINT" ,"SELECT" ,"SET" ,"SHOW" ,"START" ,"TRUNCATE" ,"UNLISTEN" ,
531
+ "UPDATE" ,"VACUUM" ,NULL
529
532
};
530
533
531
534
static const char * const backslash_commands []= {
@@ -536,7 +539,8 @@ psql_completion(char *text, int start, int end)
536
539
"\\e" ,"\\echo" ,"\\encoding" ,
537
540
"\\f" ,"\\g" ,"\\h" ,"\\help" ,"\\H" ,"\\i" ,"\\l" ,
538
541
"\\lo_import" ,"\\lo_export" ,"\\lo_list" ,"\\lo_unlink" ,
539
- "\\o" ,"\\p" ,"\\password" ,"\\pset" ,"\\q" ,"\\qecho" ,"\\r" ,"\\set" ,"\\t" ,"\\T" ,
542
+ "\\o" ,"\\p" ,"\\password" ,"\\pset" ,"\\q" ,"\\qecho" ,"\\r" ,
543
+ "\\set" ,"\\t" ,"\\T" ,
540
544
"\\timing" ,"\\unset" ,"\\x" ,"\\w" ,"\\z" ,"\\!" ,NULL
541
545
};
542
546
@@ -570,15 +574,19 @@ psql_completion(char *text, int start, int end)
570
574
else if (!prev_wd )
571
575
COMPLETE_WITH_LIST (sql_commands );
572
576
573
- /* CREATE or DROP but not ALTER (TABLE|DOMAIN|GROUP) sth DROP */
574
- /* complete with something you can create or drop */
575
- else if (pg_strcasecmp (prev_wd ,"CREATE" )== 0 ||
576
- (pg_strcasecmp (prev_wd ,"DROP" )== 0 &&
577
- pg_strcasecmp (prev3_wd ,"TABLE" )!= 0 &&
578
- pg_strcasecmp (prev3_wd ,"DOMAIN" )!= 0 &&
579
- pg_strcasecmp (prev3_wd ,"GROUP" )!= 0 ))
577
+ /* CREATE */
578
+ /* complete with something you can create */
579
+ else if (pg_strcasecmp (prev_wd ,"CREATE" )== 0 )
580
580
matches = completion_matches (text ,create_command_generator );
581
581
582
+ /* DROP, except ALTER (TABLE|DOMAIN|GROUP) sth DROP */
583
+ /* complete with something you can drop */
584
+ else if (pg_strcasecmp (prev_wd ,"DROP" )== 0 &&
585
+ pg_strcasecmp (prev3_wd ,"TABLE" )!= 0 &&
586
+ pg_strcasecmp (prev3_wd ,"DOMAIN" )!= 0 &&
587
+ pg_strcasecmp (prev3_wd ,"GROUP" )!= 0 )
588
+ matches = completion_matches (text ,drop_command_generator );
589
+
582
590
/* ALTER */
583
591
584
592
/*
@@ -1248,23 +1256,22 @@ psql_completion(char *text, int start, int end)
1248
1256
pg_strcasecmp (prev3_wd ,"AGGREGATE" )== 0 &&
1249
1257
prev_wd [strlen (prev_wd )- 1 ]== ')' ))
1250
1258
{
1251
-
1252
1259
if ((pg_strcasecmp (prev3_wd ,"DROP" )== 0 )&& (pg_strcasecmp (prev2_wd ,"FUNCTION" )== 0 ))
1253
- {
1254
- if (find_open_parenthesis (end ))
1260
+ {
1261
+ if (find_open_parenthesis (end ))
1255
1262
{
1256
1263
static const char func_args_query []= "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'" ;
1257
- char * tmp_buf = malloc (strlen (func_args_query )+ strlen (prev_wd ));
1258
- sprintf (tmp_buf ,func_args_query ,prev_wd );
1259
- COMPLETE_WITH_QUERY (tmp_buf );
1260
- free (tmp_buf );
1264
+ char * tmp_buf = malloc (strlen (func_args_query )+ strlen (prev_wd ));
1265
+ sprintf (tmp_buf ,func_args_query ,prev_wd );
1266
+ COMPLETE_WITH_QUERY (tmp_buf );
1267
+ free (tmp_buf );
1261
1268
}
1262
1269
else
1263
1270
{
1264
- COMPLETE_WITH_CONST ("(" );
1271
+ COMPLETE_WITH_CONST ("(" );
1265
1272
}
1266
- }
1267
- else
1273
+ }
1274
+ else
1268
1275
{
1269
1276
static const char * const list_DROPCR []=
1270
1277
{"CASCADE" ,"RESTRICT" ,NULL };
@@ -1274,14 +1281,22 @@ psql_completion(char *text, int start, int end)
1274
1281
}
1275
1282
else if (pg_strcasecmp (prev4_wd ,"DROP" )== 0 &&
1276
1283
pg_strcasecmp (prev3_wd ,"FUNCTION" )== 0 &&
1277
- pg_strcasecmp (prev_wd ,"(" )== 0 )
1284
+ pg_strcasecmp (prev_wd ,"(" )== 0 )
1278
1285
{
1279
1286
static const char func_args_query []= "select pg_catalog.oidvectortypes(proargtypes)||')' from pg_proc where proname='%s'" ;
1280
1287
char * tmp_buf = malloc (strlen (func_args_query )+ strlen (prev2_wd ));
1281
1288
sprintf (tmp_buf ,func_args_query ,prev2_wd );
1282
1289
COMPLETE_WITH_QUERY (tmp_buf );
1283
1290
free (tmp_buf );
1284
1291
}
1292
+ /* DROP OWNED BY */
1293
+ else if (pg_strcasecmp (prev2_wd ,"DROP" )== 0 &&
1294
+ pg_strcasecmp (prev_wd ,"OWNED" )== 0 )
1295
+ COMPLETE_WITH_CONST ("BY" );
1296
+ else if (pg_strcasecmp (prev3_wd ,"DROP" )== 0 &&
1297
+ pg_strcasecmp (prev2_wd ,"OWNED" )== 0 &&
1298
+ pg_strcasecmp (prev_wd ,"BY" )== 0 )
1299
+ COMPLETE_WITH_QUERY (Query_for_list_of_roles );
1285
1300
1286
1301
1287
1302
@@ -1502,7 +1517,7 @@ psql_completion(char *text, int start, int end)
1502
1517
else if (pg_strcasecmp (prev_wd ,"NOTIFY" )== 0 )
1503
1518
COMPLETE_WITH_QUERY ("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'" );
1504
1519
1505
- /* OWNER TO - complete with available roles*/
1520
+ /* OWNER TO - complete with available roles */
1506
1521
else if (pg_strcasecmp (prev2_wd ,"OWNER" )== 0 &&
1507
1522
pg_strcasecmp (prev_wd ,"TO" )== 0 )
1508
1523
COMPLETE_WITH_QUERY (Query_for_list_of_roles );
@@ -1526,6 +1541,25 @@ psql_completion(char *text, int start, int end)
1526
1541
COMPLETE_WITH_LIST (list_PREPARE );
1527
1542
}
1528
1543
1544
+ /* REASSIGN OWNED BY xxx TO yyy */
1545
+ else if (pg_strcasecmp (prev_wd ,"REASSIGN" )== 0 )
1546
+ COMPLETE_WITH_CONST ("OWNED" );
1547
+ else if (pg_strcasecmp (prev_wd ,"OWNED" )== 0 &&
1548
+ pg_strcasecmp (prev2_wd ,"REASSIGN" )== 0 )
1549
+ COMPLETE_WITH_CONST ("BY" );
1550
+ else if (pg_strcasecmp (prev_wd ,"BY" )== 0 &&
1551
+ pg_strcasecmp (prev2_wd ,"OWNED" )== 0 &&
1552
+ pg_strcasecmp (prev3_wd ,"REASSIGN" )== 0 )
1553
+ COMPLETE_WITH_QUERY (Query_for_list_of_roles );
1554
+ else if (pg_strcasecmp (prev2_wd ,"BY" )== 0 &&
1555
+ pg_strcasecmp (prev3_wd ,"OWNED" )== 0 &&
1556
+ pg_strcasecmp (prev4_wd ,"REASSIGN" )== 0 )
1557
+ COMPLETE_WITH_CONST ("TO" );
1558
+ else if (pg_strcasecmp (prev_wd ,"TO" )== 0 &&
1559
+ pg_strcasecmp (prev3_wd ,"BY" )== 0 &&
1560
+ pg_strcasecmp (prev4_wd ,"OWNED" )== 0 &&
1561
+ pg_strcasecmp (prev5_wd ,"REASSIGN" )== 0 )
1562
+ COMPLETE_WITH_QUERY (Query_for_list_of_roles );
1529
1563
1530
1564
/* REINDEX */
1531
1565
else if (pg_strcasecmp (prev_wd ,"REINDEX" )== 0 )
@@ -1909,7 +1943,7 @@ psql_completion(char *text, int start, int end)
1909
1943
something of that sort.
1910
1944
*/
1911
1945
1912
- /* This one gives you one from a list of things you can put after CREATE or DROP
1946
+ /* This one gives you one from a list of things you can put after CREATE
1913
1947
as defined above.
1914
1948
*/
1915
1949
static char *
@@ -1935,6 +1969,51 @@ create_command_generator(const char *text, int state)
1935
1969
return NULL ;
1936
1970
}
1937
1971
1972
+ /*
1973
+ * This function gives you a list of things you can put after a DROP command.
1974
+ * Very similar to create_command_generator, but has an additional entry for
1975
+ * OWNED BY. (We do it this way in order not to duplicate the
1976
+ * words_after_create list.)
1977
+ */
1978
+ static char *
1979
+ drop_command_generator (const char * text ,int state )
1980
+ {
1981
+ static int list_index ,
1982
+ string_length ;
1983
+ const char * name ;
1984
+
1985
+ if (state == 0 )
1986
+ {
1987
+ /* If this is the first time for this completion, init some values */
1988
+ list_index = 0 ;
1989
+ string_length = strlen (text );
1990
+
1991
+ /*
1992
+ * DROP can be followed by "OWNED BY", which is not found in the list
1993
+ * for CREATE matches, so make it the first state. (We do not make it
1994
+ * the last state because it would be more difficult to detect when we
1995
+ * have to return NULL instead.)
1996
+ *
1997
+ * Make sure we advance to the next state.
1998
+ */
1999
+ list_index ++ ;
2000
+ if (pg_strncasecmp ("OWNED" ,text ,string_length )== 0 )
2001
+ return pg_strdup ("OWNED" );
2002
+ }
2003
+
2004
+ /*
2005
+ * In subsequent attempts, try to complete with the same items we use for
2006
+ * CREATE
2007
+ */
2008
+ while ((name = words_after_create [list_index ++ - 1 ].name ))
2009
+ {
2010
+ if (pg_strncasecmp (name ,text ,string_length )== 0 )
2011
+ return pg_strdup (name );
2012
+ }
2013
+
2014
+ /* if nothing matches, return NULL */
2015
+ return NULL ;
2016
+ }
1938
2017
1939
2018
/* The following two functions are wrappers for _complete_from_query */
1940
2019