Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
0365c51e
Commit
0365c51e
authored
Nov 14, 1996
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Overhaul MainLoop input processing for quotes, comments, backslashes.
parent
f64b8403
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
1391 additions
and
1348 deletions
+1391
-1348
src/bin/psql/psql.c
src/bin/psql/psql.c
+1386
-1346
src/bin/psql/stringutils.c
src/bin/psql/stringutils.c
+5
-2
No files found.
src/bin/psql/psql.c
View file @
0365c51e
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.2
8 1996/11/11 05:55:30
momjian Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.2
9 1996/11/14 16:08:03
momjian Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -47,509 +47,504 @@
...
@@ -47,509 +47,504 @@
#define DEFAULT_SHELL "/bin/sh"
#define DEFAULT_SHELL "/bin/sh"
typedef
struct
_psqlSettings
{
typedef
struct
_psqlSettings
{
PGconn
*
db
;
/* connection to backend */
PGconn
*
db
;
/* connection to backend */
FILE
*
queryFout
;
/* where to send the query results */
FILE
*
queryFout
;
/* where to send the query results */
PQprintOpt
opt
;
/* options to be passed to PQprint */
PQprintOpt
opt
;
/* options to be passed to PQprint */
char
*
prompt
;
/* prompt to display */
char
*
prompt
;
/* prompt to display */
char
*
gfname
;
/* one-shot file output argument for \g */
char
*
gfname
;
/* one-shot file output argument for \g */
bool
notty
;
/* input or output is not a tty */
bool
notty
;
/* input or output is not a tty */
bool
pipe
;
/* queryFout is from a popen() */
bool
pipe
;
/* queryFout is from a popen() */
bool
echoQuery
;
/* echo the query before sending it */
bool
echoQuery
;
/* echo the query before sending it */
bool
quiet
;
/* run quietly, no messages, no promt */
bool
quiet
;
/* run quietly, no messages, no promt */
bool
singleStep
;
/* prompt before for each query */
bool
singleStep
;
/* prompt before for each query */
bool
singleLineMode
;
/* query terminated by newline */
bool
singleLineMode
;
/* query terminated by newline */
bool
useReadline
;
/* use libreadline routines */
bool
useReadline
;
/* use libreadline routines */
}
PsqlSettings
;
}
PsqlSettings
;
/* declarations for functions in this file */
/* declarations for functions in this file */
static
void
usage
(
char
*
progname
);
static
void
usage
(
char
*
progname
);
static
void
slashUsage
();
static
void
slashUsage
();
static
void
handleCopyOut
(
PGresult
*
res
,
bool
quiet
,
FILE
*
copystream
);
static
void
handleCopyOut
(
PGresult
*
res
,
bool
quiet
,
FILE
*
copystream
);
static
void
handleCopyIn
(
PGresult
*
res
,
const
bool
mustprompt
,
static
void
FILE
*
copystream
);
handleCopyIn
(
PGresult
*
res
,
const
bool
mustprompt
,
static
int
tableList
(
PsqlSettings
*
ps
,
bool
deep_tablelist
);
FILE
*
copystream
);
static
int
tableDesc
(
PsqlSettings
*
ps
,
char
*
table
);
static
int
tableList
(
PsqlSettings
*
ps
,
bool
deep_tablelist
);
static
int
tableDesc
(
PsqlSettings
*
ps
,
char
*
table
);
char
*
gets_noreadline
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_readline
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_noreadline
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_fromFile
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_readline
(
char
*
prompt
,
FILE
*
source
);
int
listAllDbs
(
PsqlSettings
*
settings
);
char
*
gets_fromFile
(
char
*
prompt
,
FILE
*
source
);
void
SendQuery
(
bool
*
success_p
,
PsqlSettings
*
settings
,
const
char
*
query
,
int
listAllDbs
(
PsqlSettings
*
settings
);
const
bool
copy_in
,
const
bool
copy_out
,
FILE
*
copystream
);
void
int
HandleSlashCmds
(
PsqlSettings
*
settings
,
SendQuery
(
bool
*
success_p
,
PsqlSettings
*
settings
,
const
char
*
query
,
char
*
line
,
const
bool
copy_in
,
const
bool
copy_out
,
FILE
*
copystream
);
char
*
query
);
int
int
MainLoop
(
PsqlSettings
*
settings
,
FILE
*
source
);
HandleSlashCmds
(
PsqlSettings
*
settings
,
char
*
line
,
char
*
query
);
int
MainLoop
(
PsqlSettings
*
settings
,
FILE
*
source
);
/* probably should move this into libpq */
/* probably should move this into libpq */
void
PQprint
(
FILE
*
fp
,
void
PGresult
*
res
,
PQprint
(
FILE
*
fp
,
PQprintOpt
*
po
PGresult
*
res
,
);
PQprintOpt
*
po
);
FILE
*
setFout
(
PsqlSettings
*
ps
,
char
*
fname
);
FILE
*
setFout
(
PsqlSettings
*
ps
,
char
*
fname
);
/*
/*
* usage
* usage print out usage for command line arguments
* print out usage for command line arguments
*/
*/
static
void
static
void
usage
(
char
*
progname
)
usage
(
char
*
progname
)
{
{
fprintf
(
stderr
,
"Usage: %s [options] [dbname]
\n
"
,
progname
);
fprintf
(
stderr
,
"Usage: %s [options] [dbname]
\n
"
,
progname
);
fprintf
(
stderr
,
"
\t
-a authsvc set authentication service
\n
"
);
fprintf
(
stderr
,
"
\t
-a authsvc set authentication service
\n
"
);
fprintf
(
stderr
,
"
\t
-A turn off alignment when printing out attributes
\n
"
);
fprintf
(
stderr
,
"
\t
-A turn off alignment when printing out attributes
\n
"
);
fprintf
(
stderr
,
"
\t
-c query run single query (slash commands too)
\n
"
);
fprintf
(
stderr
,
"
\t
-c query run single query (slash commands too)
\n
"
);
fprintf
(
stderr
,
"
\t
-d dbName specify database name
\n
"
);
fprintf
(
stderr
,
"
\t
-d dbName specify database name
\n
"
);
fprintf
(
stderr
,
"
\t
-e echo the query sent to the backend
\n
"
);
fprintf
(
stderr
,
"
\t
-e echo the query sent to the backend
\n
"
);
fprintf
(
stderr
,
"
\t
-f filename use file as a source of queries
\n
"
);
fprintf
(
stderr
,
"
\t
-f filename use file as a source of queries
\n
"
);
fprintf
(
stderr
,
"
\t
-F sep set the field separator (default is "
")
\n
"
);
fprintf
(
stderr
,
"
\t
-F sep set the field separator (default is "
")
\n
"
);
fprintf
(
stderr
,
"
\t
-h host set database server host
\n
"
);
fprintf
(
stderr
,
"
\t
-h host set database server host
\n
"
);
fprintf
(
stderr
,
"
\t
-H turn on html3.0 table output
\n
"
);
fprintf
(
stderr
,
"
\t
-H turn on html3.0 table output
\n
"
);
fprintf
(
stderr
,
"
\t
-l list available databases
\n
"
);
fprintf
(
stderr
,
"
\t
-l list available databases
\n
"
);
fprintf
(
stderr
,
"
\t
-n don't use readline library
\n
"
);
fprintf
(
stderr
,
"
\t
-n don't use readline library
\n
"
);
fprintf
(
stderr
,
"
\t
-o filename send output to filename or (|pipe)
\n
"
);
fprintf
(
stderr
,
"
\t
-o filename send output to filename or (|pipe)
\n
"
);
fprintf
(
stderr
,
"
\t
-p port set port number
\n
"
);
fprintf
(
stderr
,
"
\t
-p port set port number
\n
"
);
fprintf
(
stderr
,
"
\t
-q run quietly (no messages, no prompts)
\n
"
);
fprintf
(
stderr
,
"
\t
-q run quietly (no messages, no prompts)
\n
"
);
fprintf
(
stderr
,
"
\t
-s single step mode (prompts for each query)
\n
"
);
fprintf
(
stderr
,
"
\t
-s single step mode (prompts for each query)
\n
"
);
fprintf
(
stderr
,
"
\t
-S single line mode (i.e. query terminated by newline)
\n
"
);
fprintf
(
stderr
,
"
\t
-S single line mode (i.e. query terminated by newline)
\n
"
);
fprintf
(
stderr
,
"
\t
-t turn off printing of headings and row count
\n
"
);
fprintf
(
stderr
,
"
\t
-t turn off printing of headings and row count
\n
"
);
fprintf
(
stderr
,
"
\t
-T html set html3.0 table command options (cf. -H)
\n
"
);
fprintf
(
stderr
,
"
\t
-T html set html3.0 table command options (cf. -H)
\n
"
);
fprintf
(
stderr
,
"
\t
-x turn on expanded output (field names on left)
\n
"
);
fprintf
(
stderr
,
"
\t
-x turn on expanded output (field names on left)
\n
"
);
exit
(
1
);
exit
(
1
);
}
}
/*
/*
* slashUsage
* slashUsage print out usage for the backslash commands
* print out usage for the backslash commands
*/
*/
static
char
*
on
(
bool
f
)
static
char
*
on
(
bool
f
)
{
{
return
f
?
"on"
:
"off"
;
return
f
?
"on"
:
"off"
;
}
}
static
void
static
void
slashUsage
(
PsqlSettings
*
ps
)
slashUsage
(
PsqlSettings
*
ps
)
{
{
fprintf
(
stderr
,
"
\t
\\
? -- help
\n
"
);
fprintf
(
stderr
,
"
\\
? -- help
\n
"
);
fprintf
(
stderr
,
"
\t
\\
a -- toggle field-alignment (currenty %s)
\n
"
,
on
(
ps
->
opt
.
align
));
fprintf
(
stderr
,
"
\\
a -- toggle field-alignment (currenty %s)
\n
"
,
on
(
ps
->
opt
.
align
));
fprintf
(
stderr
,
"
\t
\\
C [<captn>] -- set html3 caption (currently '%s')
\n
"
,
ps
->
opt
.
caption
?
ps
->
opt
.
caption
:
""
);
fprintf
(
stderr
,
"
\\
C [<captn>] -- set html3 caption (currently '%s')
\n
"
,
ps
->
opt
.
caption
?
ps
->
opt
.
caption
:
""
);
fprintf
(
stderr
,
"
\t
\\
connect <dbname> -- connect to new database (currently '%s')
\n
"
,
PQdb
(
ps
->
db
));
fprintf
(
stderr
,
"
\\
connect <dbname> -- connect to new database (currently '%s')
\n
"
,
PQdb
(
ps
->
db
));
fprintf
(
stderr
,
"
\t
\\
copy <dbname> -- copy table to/from a file
\n
"
);
fprintf
(
stderr
,
"
\\
copy <dbname> -- copy table to/from a file
\n
"
);
fprintf
(
stderr
,
"
\t
\\
d [<table>] -- list tables in database or columns in <table>,* for all
\n
"
);
fprintf
(
stderr
,
"
\\
d [<table>] -- list tables in database or columns in <table>, * for all
\n
"
);
fprintf
(
stderr
,
"
\t
\\
e [<fname>] -- edit the current query buffer or <fname>,
\\
E execute too
\n
"
);
fprintf
(
stderr
,
"
\\
e [<fname>] -- edit the current query buffer or <fname>,
\\
E execute too
\n
"
);
fprintf
(
stderr
,
"
\t
\\
f [<sep>] -- change field separater (currently '%s')
\n
"
,
ps
->
opt
.
fieldSep
);
fprintf
(
stderr
,
"
\\
f [<sep>] -- change field separater (currently '%s')
\n
"
,
ps
->
opt
.
fieldSep
);
fprintf
(
stderr
,
"
\t
\\
g [<fname>] -- send query to backend [and place results in <fname>]
\n
"
);
fprintf
(
stderr
,
"
\\
g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]
\n
"
);
fprintf
(
stderr
,
"
\t
\\
g |<cmd> -- send query to backend and pipe results into <cmd>
\n
"
);
fprintf
(
stderr
,
"
\\
h [<cmd>] -- help on syntax of sql commands, * for all commands
\n
"
);
fprintf
(
stderr
,
"
\t
\\
h [<cmd>] -- help on syntax of sql commands, * for all commands
\n
"
);
fprintf
(
stderr
,
"
\\
H -- toggle html3 output (currently %s)
\n
"
,
on
(
ps
->
opt
.
html3
));
fprintf
(
stderr
,
"
\t
\\
H -- toggle html3 output (currently %s)
\n
"
,
on
(
ps
->
opt
.
html3
));
fprintf
(
stderr
,
"
\\
i <fname> -- read and execute queries from filename
\n
"
);
fprintf
(
stderr
,
"
\t
\\
i <fname> -- read and execute queries from filename
\n
"
);
fprintf
(
stderr
,
"
\\
l -- list all databases
\n
"
);
fprintf
(
stderr
,
"
\t
\\
l -- list all databases
\n
"
);
fprintf
(
stderr
,
"
\\
m -- toggle monitor-like table display (currently %s)
\n
"
,
on
(
ps
->
opt
.
standard
));
fprintf
(
stderr
,
"
\t
\\
m -- toggle monitor-like table display (currently %s)
\n
"
,
on
(
ps
->
opt
.
standard
));
fprintf
(
stderr
,
"
\\
o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe
\n
"
);
fprintf
(
stderr
,
"
\t
\\
o [<fname>] -- send all query results to <fname> or stdout
\n
"
);
fprintf
(
stderr
,
"
\\
p -- print the current query buffer
\n
"
);
fprintf
(
stderr
,
"
\t
\\
o |<cmd> -- pipe all query results through <cmd>
\n
"
);
fprintf
(
stderr
,
"
\\
q -- quit
\n
"
);
fprintf
(
stderr
,
"
\t
\\
p -- print the current query buffer
\n
"
);
fprintf
(
stderr
,
"
\\
r -- reset(clear) the query buffer
\n
"
);
fprintf
(
stderr
,
"
\t
\\
q -- quit
\n
"
);
fprintf
(
stderr
,
"
\\
s [<fname>] -- print history or save it in <fname>
\n
"
);
fprintf
(
stderr
,
"
\t
\\
r -- reset(clear) the query buffer
\n
"
);
fprintf
(
stderr
,
"
\\
t -- toggle table headings and row count (currently %s)
\n
"
,
on
(
ps
->
opt
.
header
));
fprintf
(
stderr
,
"
\t
\\
s [<fname>] -- print history or save it in <fname>
\n
"
);
fprintf
(
stderr
,
"
\\
T [<html>] -- set html3.0 <table ...> options (currently '%s')
\n
"
,
ps
->
opt
.
tableOpt
?
ps
->
opt
.
tableOpt
:
""
);
fprintf
(
stderr
,
"
\t
\\
t -- toggle table headings and row count (currently %s)
\n
"
,
on
(
ps
->
opt
.
header
));
fprintf
(
stderr
,
"
\\
x -- toggle expanded output (currently %s)
\n
"
,
on
(
ps
->
opt
.
expanded
));
fprintf
(
stderr
,
"
\t
\\
T [<html>] -- set html3.0 <table ...> options (currently '%s')
\n
"
,
ps
->
opt
.
tableOpt
?
ps
->
opt
.
tableOpt
:
""
);
fprintf
(
stderr
,
"
\\
! [<cmd>] -- shell escape or command
\n
"
);
fprintf
(
stderr
,
"
\t
\\
x -- toggle expanded output (currently %s)
\n
"
,
on
(
ps
->
opt
.
expanded
));
fprintf
(
stderr
,
"
\t
\\
! [<cmd>] -- shell escape or command
\n
"
);
}
}
static
PGresult
*
static
PGresult
*
PSQLexec
(
PsqlSettings
*
ps
,
char
*
query
)
PSQLexec
(
PsqlSettings
*
ps
,
char
*
query
)
{
{
PGresult
*
res
=
PQexec
(
ps
->
db
,
query
);
PGresult
*
res
=
PQexec
(
ps
->
db
,
query
);
if
(
!
res
)
if
(
!
res
)
fputs
(
PQerrorMessage
(
ps
->
db
),
stderr
);
fputs
(
PQerrorMessage
(
ps
->
db
),
stderr
);
else
else
{
{
if
(
PQresultStatus
(
res
)
==
PGRES_COMMAND_OK
||
if
(
PQresultStatus
(
res
)
==
PGRES_COMMAND_OK
||
PQresultStatus
(
res
)
==
PGRES_TUPLES_OK
)
PQresultStatus
(
res
)
==
PGRES_TUPLES_OK
)
return
res
;
return
res
;
if
(
!
ps
->
quiet
)
if
(
!
ps
->
quiet
)
fputs
(
PQerrorMessage
(
ps
->
db
),
stderr
);
fputs
(
PQerrorMessage
(
ps
->
db
),
stderr
);
PQclear
(
res
);
PQclear
(
res
);
}
}
return
NULL
;
return
NULL
;
}
}
/*
/*
* listAllDbs
* listAllDbs
*
*
* list all the databases in the system
* list all the databases in the system returns 0 if all went well
* returns 0 if all went well
*
*
*
*
*/
*/
int
int
listAllDbs
(
PsqlSettings
*
ps
)
listAllDbs
(
PsqlSettings
*
ps
)
{
{
PGresult
*
results
;
PGresult
*
results
;
char
*
query
=
"select * from pg_database;"
;
char
*
query
=
"select * from pg_database;"
;
if
(
!
(
results
=
PSQLexec
(
ps
,
query
)))
if
(
!
(
results
=
PSQLexec
(
ps
,
query
)))
return
1
;
return
1
;
else
else
{
{
PQprint
(
ps
->
queryFout
,
PQprint
(
ps
->
queryFout
,
results
,
results
,
&
ps
->
opt
);
&
ps
->
opt
);
PQclear
(
results
);
PQclear
(
results
);
return
0
;
return
0
;
}
}
}
}
/*
/*
*
* List The Database Tables returns 0 if all went well
* List The Database Tables
*
* returns 0 if all went well
*
*/
*/
int
int
tableList
(
PsqlSettings
*
ps
,
bool
deep_tablelist
)
tableList
(
PsqlSettings
*
ps
,
bool
deep_tablelist
)
{
{
char
listbuf
[
256
];
char
listbuf
[
256
];
int
nColumns
;
int
nColumns
;
int
i
;
int
i
;
char
*
rk
;
char
*
rk
;
char
*
rr
;
char
*
rr
;
PGresult
*
res
;
PGresult
*
res
;
listbuf
[
0
]
=
'\0'
;
listbuf
[
0
]
=
'\0'
;
strcat
(
listbuf
,
"SELECT usename, relname, relkind, relhasrules"
);
strcat
(
listbuf
,
"SELECT usename, relname, relkind, relhasrules"
);
strcat
(
listbuf
,
" FROM pg_class, pg_user "
);
strcat
(
listbuf
,
" FROM pg_class, pg_user "
);
strcat
(
listbuf
,
"WHERE ( relkind = 'r' OR relkind = 'i') "
);
strcat
(
listbuf
,
"WHERE ( relkind = 'r' OR relkind = 'i') "
);
strcat
(
listbuf
,
" and relname !~ '^pg_'"
);
strcat
(
listbuf
,
" and relname !~ '^pg_'"
);
strcat
(
listbuf
,
" and relname !~ '^Inv[0-9]+'"
);
strcat
(
listbuf
,
" and relname !~ '^Inv[0-9]+'"
);
/* the usesysid = relowner won't work on stock 1.0 dbs, need to
/*
add in the int4oideq function */
* the usesysid = relowner won't work on stock 1.0 dbs, need to add in
strcat
(
listbuf
,
" and usesysid = relowner"
);
* the int4oideq function
strcat
(
listbuf
,
" ORDER BY relname "
);
*/
if
(
!
(
res
=
PSQLexec
(
ps
,
listbuf
)))
strcat
(
listbuf
,
" and usesysid = relowner"
);
return
-
1
;
strcat
(
listbuf
,
" ORDER BY relname "
);
if
(
!
(
res
=
PSQLexec
(
ps
,
listbuf
)))
/* first, print out the attribute names */
return
-
1
;
nColumns
=
PQntuples
(
res
);
if
(
nColumns
>
0
)
/* first, print out the attribute names */
{
nColumns
=
PQntuples
(
res
);
if
(
deep_tablelist
)
{
if
(
nColumns
>
0
)
{
/* describe everything here */
if
(
deep_tablelist
)
{
char
**
table
;
/* describe everything here */
table
=
(
char
**
)
malloc
(
nColumns
*
sizeof
(
char
*
));
char
**
table
;
if
(
table
==
NULL
)
table
=
(
char
**
)
malloc
(
nColumns
*
sizeof
(
char
*
));
perror
(
"malloc"
);
if
(
table
==
NULL
)
perror
(
"malloc"
);
/* load table table */
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
/* load table table */
table
[
i
]
=
(
char
*
)
malloc
(
PQgetlength
(
res
,
i
,
1
)
*
sizeof
(
char
)
+
1
);
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
if
(
table
[
i
]
==
NULL
)
table
[
i
]
=
(
char
*
)
malloc
(
PQgetlength
(
res
,
i
,
1
)
*
sizeof
(
char
)
+
1
);
perror
(
"malloc"
);
if
(
table
[
i
]
==
NULL
)
strcpy
(
table
[
i
],
PQgetvalue
(
res
,
i
,
1
));
perror
(
"malloc"
);
}
strcpy
(
table
[
i
],
PQgetvalue
(
res
,
i
,
1
));
}
PQclear
(
res
);
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
PQclear
(
res
);
tableDesc
(
ps
,
table
[
i
]);
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
}
tableDesc
(
ps
,
table
[
i
]);
free
(
table
);
}
}
free
(
table
);
else
{
}
else
{
/* Display the information */
/* Display the information */
printf
(
"
\n
Database = %s
\n
"
,
PQdb
(
ps
->
db
));
printf
(
"
\n
Database = %s
\n
"
,
PQdb
(
ps
->
db
));
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
printf
(
" | Owner | Relation | Type |
\n
"
);
printf
(
" | Owner | Relation | Type |
\n
"
);
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
/* next, print out the instances */
/* next, print out the instances */
for
(
i
=
0
;
i
<
PQntuples
(
res
);
i
++
)
{
for
(
i
=
0
;
i
<
PQntuples
(
res
);
i
++
)
{
printf
(
" | %-16.16s"
,
PQgetvalue
(
res
,
i
,
0
));
printf
(
" | %-16.16s"
,
PQgetvalue
(
res
,
i
,
0
));
printf
(
" | %-32.32s | "
,
PQgetvalue
(
res
,
i
,
1
));
printf
(
" | %-32.32s | "
,
PQgetvalue
(
res
,
i
,
1
));
rk
=
PQgetvalue
(
res
,
i
,
2
);
rk
=
PQgetvalue
(
res
,
i
,
2
);
rr
=
PQgetvalue
(
res
,
i
,
3
);
rr
=
PQgetvalue
(
res
,
i
,
3
);
if
(
strcmp
(
rk
,
"r"
)
==
0
)
if
(
strcmp
(
rk
,
"r"
)
==
0
)
printf
(
"%-8.8s |"
,
(
rr
[
0
]
==
't'
)
?
"view?"
:
"table"
);
printf
(
"%-8.8s |"
,
(
rr
[
0
]
==
't'
)
?
"view?"
:
"table"
);
else
else
printf
(
"%-8.8s |"
,
"index"
);
printf
(
"%-8.8s |"
,
"index"
);
printf
(
"
\n
"
);
printf
(
"
\n
"
);
}
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
PQclear
(
res
);
}
return
(
0
);
}
else
{
fprintf
(
stderr
,
"Couldn't find any tables!
\n
"
);
return
(
-
1
);
}
}
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
PQclear
(
res
);
}
return
(
0
);
}
else
{
fprintf
(
stderr
,
"Couldn't find any tables!
\n
"
);
return
(
-
1
);
}
}
}
/*
/*
* Describe a table
* Describe a table
*
*
* Describe the columns in a database table.
* Describe the columns in a database table. returns 0 if all went well
* returns 0 if all went well
*
*
*
*
*/
*/
int
int
tableDesc
(
PsqlSettings
*
ps
,
char
*
table
)
tableDesc
(
PsqlSettings
*
ps
,
char
*
table
)
{
{
char
descbuf
[
256
];
char
descbuf
[
256
];
int
nColumns
;
int
nColumns
;
char
*
rtype
;
char
*
rtype
;
int
i
;
int
i
;
int
rsize
;
int
rsize
;
PGresult
*
res
;
PGresult
*
res
;
/* Build the query */
/* Build the query */
descbuf
[
0
]
=
'\0'
;
descbuf
[
0
]
=
'\0'
;
strcat
(
descbuf
,
"SELECT a.attnum, a.attname, t.typname, a.attlen"
);
strcat
(
descbuf
,
"SELECT a.attnum, a.attname, t.typname, a.attlen"
);
strcat
(
descbuf
,
" FROM pg_class c, pg_attribute a, pg_type t "
);
strcat
(
descbuf
,
" FROM pg_class c, pg_attribute a, pg_type t "
);
strcat
(
descbuf
,
" WHERE c.relname = '"
);
strcat
(
descbuf
,
" WHERE c.relname = '"
);
strcat
(
descbuf
,
table
);
strcat
(
descbuf
,
table
);
strcat
(
descbuf
,
"'"
);
strcat
(
descbuf
,
"'"
);
strcat
(
descbuf
,
" and a.attnum > 0 "
);
strcat
(
descbuf
,
" and a.attnum > 0 "
);
strcat
(
descbuf
,
" and a.attrelid = c.oid "
);
strcat
(
descbuf
,
" and a.attrelid = c.oid "
);
strcat
(
descbuf
,
" and a.atttypid = t.oid "
);
strcat
(
descbuf
,
" and a.atttypid = t.oid "
);
strcat
(
descbuf
,
" ORDER BY attnum "
);
strcat
(
descbuf
,
" ORDER BY attnum "
);
if
(
!
(
res
=
PSQLexec
(
ps
,
descbuf
)))
if
(
!
(
res
=
PSQLexec
(
ps
,
descbuf
)))
return
-
1
;
return
-
1
;
/* first, print out the attribute names */
/* first, print out the attribute names */
nColumns
=
PQntuples
(
res
);
nColumns
=
PQntuples
(
res
);
if
(
nColumns
>
0
)
if
(
nColumns
>
0
)
{
{
/*
/*
* * Display the information
** Display the information
*/
*/
printf
(
"
\n
Table = %s
\n
"
,
table
);
printf
(
"
\n
Table = %s
\n
"
,
table
);
printf
(
"+----------------------------------+----------------------------------+-------+
\n
"
);
printf
(
"+----------------------------------+----------------------------------+-------+
\n
"
);
printf
(
"| Field | Type | Length|
\n
"
);
printf
(
"| Field | Type | Length|
\n
"
);
printf
(
"+----------------------------------+----------------------------------+-------+
\n
"
);
printf
(
"+----------------------------------+----------------------------------+-------+
\n
"
);
/* next, print out the instances */
/* next, print out the instances */
for
(
i
=
0
;
i
<
PQntuples
(
res
);
i
++
)
{
for
(
i
=
0
;
i
<
PQntuples
(
res
);
i
++
)
{
printf
(
"| %-32.32s | "
,
PQgetvalue
(
res
,
i
,
1
));
printf
(
"| %-32.32s | "
,
PQgetvalue
(
res
,
i
,
1
));
rtype
=
PQgetvalue
(
res
,
i
,
2
);
rtype
=
PQgetvalue
(
res
,
i
,
2
);
rsize
=
atoi
(
PQgetvalue
(
res
,
i
,
3
));
rsize
=
atoi
(
PQgetvalue
(
res
,
i
,
3
));
if
(
strcmp
(
rtype
,
"text"
)
==
0
)
{
if
(
strcmp
(
rtype
,
"text"
)
==
0
)
{
printf
(
"%-32.32s |"
,
rtype
);
printf
(
"%-32.32s |"
,
rtype
);
printf
(
"%6s |"
,
"var"
);
printf
(
"%6s |"
,
"var"
);
}
else
if
(
strcmp
(
rtype
,
"bpchar"
)
==
0
)
{
}
printf
(
"%-32.32s |"
,
"(bp)char"
);
else
if
(
strcmp
(
rtype
,
"bpchar"
)
==
0
)
{
printf
(
"%6i |"
,
rsize
>
0
?
rsize
-
4
:
0
);
printf
(
"%-32.32s |"
,
"(bp)char"
);
}
else
if
(
strcmp
(
rtype
,
"varchar"
)
==
0
)
{
printf
(
"%6i |"
,
rsize
>
0
?
rsize
-
4
:
0
);
printf
(
"%-32.32s |"
,
rtype
);
}
printf
(
"%6i |"
,
rsize
>
0
?
rsize
-
4
:
0
);
else
if
(
strcmp
(
rtype
,
"varchar"
)
==
0
)
{
}
else
{
printf
(
"%-32.32s |"
,
rtype
);
/* array types start with an underscore */
printf
(
"%6i |"
,
rsize
>
0
?
rsize
-
4
:
0
);
if
(
rtype
[
0
]
!=
'_'
)
}
printf
(
"%-32.32s |"
,
rtype
);
else
{
else
{
/* array types start with an underscore */
char
*
newname
;
if
(
rtype
[
0
]
!=
'_'
)
newname
=
malloc
(
strlen
(
rtype
)
+
2
);
printf
(
"%-32.32s |"
,
rtype
);
strcpy
(
newname
,
rtype
+
1
);
else
{
strcat
(
newname
,
"[]"
);
char
*
newname
;
printf
(
"%-32.32s |"
,
newname
);
newname
=
malloc
(
strlen
(
rtype
)
+
2
);
free
(
newname
);
strcpy
(
newname
,
rtype
+
1
);
}
strcat
(
newname
,
"[]"
);
if
(
rsize
>
0
)
printf
(
"%-32.32s |"
,
newname
);
printf
(
"%6i |"
,
rsize
);
free
(
newname
);
else
}
printf
(
"%6s |"
,
"var"
);
if
(
rsize
>
0
)
}
printf
(
"%6i |"
,
rsize
);
printf
(
"
\n
"
);
else
}
printf
(
"%6s |"
,
"var"
);
printf
(
"+----------------------------------+----------------------------------+-------+
\n
"
);
}
printf
(
"
\n
"
);
PQclear
(
res
);
return
(
0
);
}
else
{
fprintf
(
stderr
,
"Couldn't find table %s!
\n
"
,
table
);
return
(
-
1
);
}
}
printf
(
"+----------------------------------+----------------------------------+-------+
\n
"
);
PQclear
(
res
);
return
(
0
);
}
else
{
fprintf
(
stderr
,
"Couldn't find table %s!
\n
"
,
table
);
return
(
-
1
);
}
}
}
typedef
char
*
(
*
READ_ROUTINE
)(
char
*
prompt
,
FILE
*
source
);
typedef
char
*
(
*
READ_ROUTINE
)
(
char
*
prompt
,
FILE
*
source
);
/* gets_noreadline prompt source
/*
gets a line of input without calling readline, the source is ignored
* gets_noreadline prompt source gets a line of input without calling
*/
* readline, the source is ignored
char
*
*/
gets_noreadline
(
char
*
prompt
,
FILE
*
source
)
char
*
gets_noreadline
(
char
*
prompt
,
FILE
*
source
)
{
{
fputs
(
prompt
,
stdout
);
fputs
(
prompt
,
stdout
);
fflush
(
stdout
);
fflush
(
stdout
);
return
(
gets_fromFile
(
prompt
,
stdin
));
return
(
gets_fromFile
(
prompt
,
stdin
));
}
}
/*
/*
* gets_readline prompt source
* gets_readline prompt source the routine to get input from GNU readline(),
* the routine to get input from GNU readline(), the source is ignored
* the source is ignored the prompt argument is used as the prompting string
* the prompt argument is used as the prompting string
*/
*/
char
*
char
*
gets_readline
(
char
*
prompt
,
FILE
*
source
)
gets_readline
(
char
*
prompt
,
FILE
*
source
)
{
{
return
(
readline
(
prompt
));
return
(
readline
(
prompt
));
}
}
/*
/*
* gets_fromFile prompt source
* gets_fromFile prompt source
*
*
* the routine to read from a file, the prompt argument is ignored
* the routine to read from a file, the prompt argument is ignored
the source
*
the source
argument is a FILE *
* argument is a FILE *
*/
*/
char
*
char
*
gets_fromFile
(
char
*
prompt
,
FILE
*
source
)
gets_fromFile
(
char
*
prompt
,
FILE
*
source
)
{
{
char
*
line
;
char
*
line
;
int
len
;
int
len
;
line
=
malloc
(
MAX_QUERY_BUFFER
+
1
);
line
=
malloc
(
MAX_QUERY_BUFFER
+
1
);
/* read up to MAX_QUERY_BUFFER characters */
/* read up to MAX_QUERY_BUFFER characters */
if
(
fgets
(
line
,
MAX_QUERY_BUFFER
,
source
)
==
NULL
)
if
(
fgets
(
line
,
MAX_QUERY_BUFFER
,
source
)
==
NULL
)
return
NULL
;
return
NULL
;
line
[
MAX_QUERY_BUFFER
-
1
]
=
'\0'
;
line
[
MAX_QUERY_BUFFER
-
1
]
=
'\0'
;
len
=
strlen
(
line
);
len
=
strlen
(
line
);
if
(
len
==
MAX_QUERY_BUFFER
)
if
(
len
==
MAX_QUERY_BUFFER
)
{
{
fprintf
(
stderr
,
"line read exceeds maximum length. Truncating at %d
\n
"
,
fprintf
(
stderr
,
"line read exceeds maximum length. Truncating at %d
\n
"
,
MAX_QUERY_BUFFER
);
MAX_QUERY_BUFFER
);
}
}
return
line
;
return
line
;
}
}
/*
/*
* SendQuery: send the query string to the backend
* SendQuery: send the query string to the backend return *success_p = 1 if
* return *success_p = 1 if the query executed successfully
* the query executed successfully returns *success_p = 0 otherwise
* returns *success_p = 0 otherwise
*/
*/
void
void
SendQuery
(
bool
*
success_p
,
PsqlSettings
*
settings
,
const
char
*
query
,
SendQuery
(
bool
*
success_p
,
PsqlSettings
*
settings
,
const
char
*
query
,
const
bool
copy_in
,
const
bool
copy_out
,
FILE
*
copystream
)
{
const
bool
copy_in
,
const
bool
copy_out
,
FILE
*
copystream
)
{
PGresult
*
results
;
PGnotify
*
notify
;
if
(
settings
->
singleStep
)
PGresult
*
results
;
fprintf
(
stdout
,
"
\n
**************************************"
PGnotify
*
notify
;
"*****************************************
\n
"
);
if
(
settings
->
echoQuery
||
settings
->
singleStep
)
{
if
(
settings
->
singleStep
)
fprintf
(
stderr
,
"QUERY: %s
\n
"
,
query
);
fprintf
(
stdout
,
"
\n
**************************************"
fflush
(
stderr
);
"*****************************************
\n
"
);
}
if
(
settings
->
singleStep
)
{
if
(
settings
->
echoQuery
||
settings
->
singleStep
)
{
fprintf
(
stdout
,
"
\n
**************************************"
fprintf
(
stderr
,
"QUERY: %s
\n
"
,
query
);
"*****************************************
\n
"
);
fflush
(
stderr
);
fflush
(
stdout
);
}
printf
(
"
\n
press return to continue ..
\n
"
);
if
(
settings
->
singleStep
)
{
gets_fromFile
(
""
,
stdin
);
fprintf
(
stdout
,
"
\n
**************************************"
}
"*****************************************
\n
"
);
fflush
(
stdout
);
results
=
PQexec
(
settings
->
db
,
query
);
printf
(
"
\n
press return to continue ..
\n
"
);
if
(
results
==
NULL
)
{
gets_fromFile
(
""
,
stdin
);
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
}
*
success_p
=
false
;
results
=
PQexec
(
settings
->
db
,
query
);
}
else
{
if
(
results
==
NULL
)
{
switch
(
PQresultStatus
(
results
))
{
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
case
PGRES_TUPLES_OK
:
*
success_p
=
false
;
if
(
settings
->
gfname
)
{
}
else
{
PsqlSettings
ps
=*
settings
;
switch
(
PQresultStatus
(
results
))
{
FILE
*
fp
;
case
PGRES_TUPLES_OK
:
ps
.
queryFout
=
stdout
;
if
(
settings
->
gfname
)
{
fp
=
setFout
(
&
ps
,
settings
->
gfname
);
PsqlSettings
ps
=
*
settings
;
if
(
!
fp
||
fp
==
stdout
)
{
FILE
*
fp
;
*
success_p
=
false
;
ps
.
queryFout
=
stdout
;
break
;
fp
=
setFout
(
&
ps
,
settings
->
gfname
);
}
else
*
success_p
=
true
;
if
(
!
fp
||
fp
==
stdout
)
{
PQprint
(
fp
,
*
success_p
=
false
;
results
,
break
;
&
(
settings
->
opt
));
}
else
if
(
ps
.
pipe
)
*
success_p
=
true
;
pclose
(
fp
);
PQprint
(
fp
,
else
results
,
fclose
(
fp
);
&
(
settings
->
opt
));
settings
->
gfname
=
NULL
;
if
(
ps
.
pipe
)
break
;
pclose
(
fp
);
}
else
{
else
*
success_p
=
true
;
fclose
(
fp
);
PQprint
(
settings
->
queryFout
,
settings
->
gfname
=
NULL
;
results
,
break
;
&
(
settings
->
opt
));
}
else
{
fflush
(
settings
->
queryFout
);
*
success_p
=
true
;
}
PQprint
(
settings
->
queryFout
,
PQclear
(
results
);
results
,
break
;
&
(
settings
->
opt
));
case
PGRES_EMPTY_QUERY
:
fflush
(
settings
->
queryFout
);
*
success_p
=
true
;
}
break
;
PQclear
(
results
);
case
PGRES_COMMAND_OK
:
break
;
*
success_p
=
true
;
case
PGRES_EMPTY_QUERY
:
if
(
!
settings
->
quiet
)
*
success_p
=
true
;
fprintf
(
stdout
,
"%s
\n
"
,
PQcmdStatus
(
results
));
break
;
break
;
case
PGRES_COMMAND_OK
:
case
PGRES_COPY_OUT
:
*
success_p
=
true
;
*
success_p
=
true
;
if
(
!
settings
->
quiet
)
if
(
copy_out
)
{
fprintf
(
stdout
,
"%s
\n
"
,
PQcmdStatus
(
results
));
handleCopyOut
(
results
,
settings
->
quiet
,
copystream
);
break
;
}
else
{
case
PGRES_COPY_OUT
:
if
(
!
settings
->
quiet
)
*
success_p
=
true
;
fprintf
(
stdout
,
"Copy command returns...
\n
"
);
if
(
copy_out
)
{
handleCopyOut
(
results
,
settings
->
quiet
,
copystream
);
handleCopyOut
(
results
,
settings
->
quiet
,
stdout
);
}
else
{
}
if
(
!
settings
->
quiet
)
break
;
fprintf
(
stdout
,
"Copy command returns...
\n
"
);
case
PGRES_COPY_IN
:
*
success_p
=
true
;
handleCopyOut
(
results
,
settings
->
quiet
,
stdout
);
if
(
copy_in
)
{
}
handleCopyIn
(
results
,
false
,
copystream
);
break
;
}
else
{
case
PGRES_COPY_IN
:
char
c
;
*
success_p
=
true
;
/*
if
(
copy_in
)
{
* eat extra newline still in input buffer
handleCopyIn
(
results
,
false
,
copystream
);
*
}
else
{
*/
char
c
;
fflush
(
stdin
);
/*
if
((
c
=
getc
(
stdin
))
!=
'\n'
&&
c
!=
EOF
)
* eat extra newline still in input buffer
(
void
)
ungetc
(
c
,
stdin
);
*
handleCopyIn
(
results
,
!
settings
->
quiet
,
stdin
);
*/
}
fflush
(
stdin
);
break
;
if
((
c
=
getc
(
stdin
))
!=
'\n'
&&
c
!=
EOF
)
case
PGRES_NONFATAL_ERROR
:
(
void
)
ungetc
(
c
,
stdin
);
case
PGRES_FATAL_ERROR
:
handleCopyIn
(
results
,
!
settings
->
quiet
,
stdin
);
case
PGRES_BAD_RESPONSE
:
}
*
success_p
=
false
;
break
;
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
case
PGRES_NONFATAL_ERROR
:
break
;
case
PGRES_FATAL_ERROR
:
}
case
PGRES_BAD_RESPONSE
:
*
success_p
=
false
;
/* check for asynchronous returns */
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
notify
=
PQnotifies
(
settings
->
db
);
break
;
if
(
notify
)
{
}
fprintf
(
stderr
,
"ASYNC NOTIFY of '%s' from backend pid '%d' received
\n
"
,
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
notify
->
relname
,
notify
->
be_pid
);
fprintf
(
stderr
,
free
(
notify
);
"We have lost the connection to the backend, so "
}
"further processing is impossible. "
}
"Terminating.
\n
"
);
exit
(
2
);
/* we are out'ta here */
}
/* check for asynchronous returns */
notify
=
PQnotifies
(
settings
->
db
);
if
(
notify
)
{
fprintf
(
stderr
,
"ASYNC NOTIFY of '%s' from backend pid '%d' received
\n
"
,
notify
->
relname
,
notify
->
be_pid
);
free
(
notify
);
}
}
}
}
...
@@ -557,985 +552,1034 @@ SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
...
@@ -557,985 +552,1034 @@ SendQuery(bool *success_p, PsqlSettings *settings, const char *query,
static
void
static
void
editFile
(
char
*
fname
)
editFile
(
char
*
fname
)
{
{
char
*
editorName
;
char
*
editorName
;
char
*
sys
;
char
*
sys
;
editorName
=
getenv
(
"EDITOR"
);
editorName
=
getenv
(
"EDITOR"
);
if
(
!
editorName
)
if
(
!
editorName
)
editorName
=
DEFAULT_EDITOR
;
editorName
=
DEFAULT_EDITOR
;
sys
=
malloc
(
strlen
(
editorName
)
+
strlen
(
fname
)
+
32
+
1
);
sys
=
malloc
(
strlen
(
editorName
)
+
strlen
(
fname
)
+
32
+
1
);
if
(
!
sys
)
if
(
!
sys
)
{
{
perror
(
"malloc"
);
perror
(
"malloc"
);
exit
(
1
);
exit
(
1
);
}
}
sprintf
(
sys
,
"exec '%s' '%s'"
,
editorName
,
fname
);
sprintf
(
sys
,
"exec '%s' '%s'"
,
editorName
,
fname
);
system
(
sys
);
system
(
sys
);
free
(
sys
);
free
(
sys
);
}
}
static
bool
static
bool
toggle
(
PsqlSettings
*
settings
,
bool
*
sw
,
char
*
msg
)
toggle
(
PsqlSettings
*
settings
,
bool
*
sw
,
char
*
msg
)
{
{
*
sw
=
!*
sw
;
*
sw
=
!*
sw
;
if
(
!
settings
->
quiet
)
if
(
!
settings
->
quiet
)
fprintf
(
stderr
,
"turned %s %s
\n
"
,
on
(
*
sw
),
msg
);
fprintf
(
stderr
,
"turned %s %s
\n
"
,
on
(
*
sw
),
msg
);
return
*
sw
;
return
*
sw
;
}
}
static
void
static
void
unescape
(
char
*
dest
,
const
char
*
source
)
{
unescape
(
char
*
dest
,
const
char
*
source
)
/*-----------------------------------------------------------------------------
{
Return as the string <dest> the value of string <source> with escape
/*-----------------------------------------------------------------------------
sequences turned into the bytes they represent.
Return as the string <dest> the value of string <source> with escape
-----------------------------------------------------------------------------*/
sequences turned into the bytes they represent.
char
*
p
;
-----------------------------------------------------------------------------*/
bool
esc
;
/* Last character we saw was the escape character (/) */
char
*
p
;
bool
esc
;
/* Last character we saw was the escape
esc
=
false
;
/* Haven't seen escape character yet */
* character (/) */
for
(
p
=
(
char
*
)
source
;
*
p
;
p
++
)
{
char
c
;
/* Our output character */
esc
=
false
;
/* Haven't seen escape character yet */
for
(
p
=
(
char
*
)
source
;
*
p
;
p
++
)
{
if
(
esc
)
{
char
c
;
/* Our output character */
switch
(
*
p
)
{
case
'n'
:
if
(
esc
)
{
c
=
'\n'
;
switch
(
*
p
)
{
break
;
case
'n'
:
case
'r'
:
c
=
'\n'
;
c
=
'\r'
;
break
;
break
;
case
'r'
:
case
't'
:
c
=
'\r'
;
c
=
'\t'
;
break
;
break
;
case
't'
:
case
'f'
:
c
=
'\t'
;
c
=
'\f'
;
break
;
break
;
case
'f'
:
case
'\\'
:
c
=
'\f'
;
c
=
'\\'
;
break
;
break
;
case
'\\'
:
default:
c
=
'\\'
;
c
=
*
p
;
break
;
}
default:
esc
=
false
;
c
=
*
p
;
}
else
}
if
(
*
p
==
'\\'
)
{
esc
=
false
;
esc
=
true
;
}
else
if
(
*
p
==
'\\'
)
{
c
=
' '
;
/* meaningless, but compiler doesn't know that */
esc
=
true
;
}
else
{
c
=
' '
;
/* meaningless, but compiler doesn't know
c
=
*
p
;
* that */
esc
=
false
;
}
else
{
}
c
=
*
p
;
if
(
!
esc
)
*
dest
++=
c
;
esc
=
false
;
}
if
(
!
esc
)
*
dest
++
=
c
;
}
}
*
dest
=
'\0'
;
/* Terminating null character */
*
dest
=
'\0'
;
/* Terminating null character */
}
}
static
void
static
void
parse_slash_copy
(
const
char
*
args
,
char
*
table
,
const
int
table_len
,
parse_slash_copy
(
const
char
*
args
,
char
*
table
,
const
int
table_len
,
char
*
file
,
const
int
file_len
,
char
*
file
,
const
int
file_len
,
bool
*
from_p
,
bool
*
error_p
)
{
bool
*
from_p
,
bool
*
error_p
)
{
char
work_args
[
200
];
/* A copy of the \copy command arguments, except that we modify it
char
work_args
[
200
];
as we parse to suit our parsing needs.
/*
*/
* A copy of the \copy command arguments, except that we modify it as we
char
*
table_tok
,
*
fromto_tok
;
* parse to suit our parsing needs.
*/
char
*
table_tok
,
*
fromto_tok
;
strncpy
(
work_args
,
args
,
sizeof
(
work_args
));
strncpy
(
work_args
,
args
,
sizeof
(
work_args
));
work_args
[
sizeof
(
work_args
)
-
1
]
=
'\0'
;
work_args
[
sizeof
(
work_args
)
-
1
]
=
'\0'
;
*
error_p
=
false
;
/* initial assumption */
*
error_p
=
false
;
/* initial assumption */
table_tok
=
strtok
(
work_args
,
" "
);
table_tok
=
strtok
(
work_args
,
" "
);
if
(
table_tok
==
NULL
)
{
if
(
table_tok
==
NULL
)
{
fprintf
(
stderr
,
"
\\
copy needs arguments.
\n
"
);
fprintf
(
stderr
,
"
\\
copy needs arguments.
\n
"
);
*
error_p
=
true
;
*
error_p
=
true
;
}
else
{
}
else
{
strncpy
(
table
,
table_tok
,
table_len
);
strncpy
(
table
,
table_tok
,
table_len
);
file
[
table_len
-
1
]
=
'\0'
;
file
[
table_len
-
1
]
=
'\0'
;
fromto_tok
=
strtok
(
NULL
,
" "
);
fromto_tok
=
strtok
(
NULL
,
" "
);
if
(
fromto_tok
==
NULL
)
{
if
(
fromto_tok
==
NULL
)
{
fprintf
(
stderr
,
"'FROM' or 'TO' must follow table name.
\n
"
);
fprintf
(
stderr
,
"'FROM' or 'TO' must follow table name.
\n
"
);
*
error_p
=
true
;
*
error_p
=
true
;
}
else
{
}
else
{
if
(
strcasecmp
(
fromto_tok
,
"from"
)
==
0
)
*
from_p
=
true
;
if
(
strcasecmp
(
fromto_tok
,
"from"
)
==
0
)
else
if
(
strcasecmp
(
fromto_tok
,
"to"
)
==
0
)
*
from_p
=
false
;
*
from_p
=
true
;
else
{
else
if
(
strcasecmp
(
fromto_tok
,
"to"
)
==
0
)
fprintf
(
stderr
,
*
from_p
=
false
;
"Unrecognized token found where "
else
{
"'FROM' or 'TO' expected: '%s'.
\n
"
,
fprintf
(
stderr
,
fromto_tok
);
"Unrecognized token found where "
*
error_p
=
true
;
"'FROM' or 'TO' expected: '%s'.
\n
"
,
}
fromto_tok
);
if
(
!*
error_p
)
{
*
error_p
=
true
;
char
*
file_tok
;
}
if
(
!*
error_p
)
{
file_tok
=
strtok
(
NULL
,
" "
);
char
*
file_tok
;
if
(
file_tok
==
NULL
)
{
fprintf
(
stderr
,
"A file pathname must follow '%s'.
\n
"
,
file_tok
=
strtok
(
NULL
,
" "
);
fromto_tok
);
if
(
file_tok
==
NULL
)
{
*
error_p
=
true
;
fprintf
(
stderr
,
"A file pathname must follow '%s'.
\n
"
,
}
else
{
fromto_tok
);
strncpy
(
file
,
file_tok
,
file_len
);
*
error_p
=
true
;
file
[
file_len
-
1
]
=
'\0'
;
}
else
{
if
(
strtok
(
NULL
,
" "
)
!=
NULL
)
{
strncpy
(
file
,
file_tok
,
file_len
);
fprintf
(
stderr
,
file
[
file_len
-
1
]
=
'\0'
;
"You have extra tokens after the filename.
\n
"
);
if
(
strtok
(
NULL
,
" "
)
!=
NULL
)
{
*
error_p
=
true
;
fprintf
(
stderr
,
}
"You have extra tokens after the filename.
\n
"
);
}
*
error_p
=
true
;
}
}
}
}
}
}
}
}
}
}
static
void
static
void
do_copy
(
const
char
*
args
,
PsqlSettings
*
settings
)
{
do_copy
(
const
char
*
args
,
PsqlSettings
*
settings
)
/*---------------------------------------------------------------------------
{
Execute a \copy command (frontend copy). We have to open a file, then
/*---------------------------------------------------------------------------
submit a COPY query to the backend and either feed it data from the
Execute a \copy command (frontend copy). We have to open a file, then
file or route its response into the file.
submit a COPY query to the backend and either feed it data from the
file or route its response into the file.
We do a text copy with default (tab) column delimiters. Some day, we
should do all the things a backend copy can do.
We do a text copy with default (tab) column delimiters. Some day, we
should do all the things a backend copy can do.
----------------------------------------------------------------------------*/
char
query
[
200
];
----------------------------------------------------------------------------*/
/* The COPY command we send to the back end */
char
query
[
200
];
bool
from
;
/* The COPY command we send to the back end */
/* The direction of the copy is from a file to a table. */
bool
from
;
char
file
[
MAXPATHLEN
+
1
];
/* The direction of the copy is from a file to a table. */
/* The pathname of the file from/to which we copy */
char
file
[
MAXPATHLEN
+
1
];
char
table
[
NAMEDATALEN
+
1
];
/* The pathname of the file from/to which we copy */
/* The name of the table from/to which we copy */
char
table
[
NAMEDATALEN
+
1
];
bool
syntax_error
;
/* The name of the table from/to which we copy */
/* The \c command has invalid syntax */
bool
syntax_error
;
FILE
*
copystream
;
/* The \c command has invalid syntax */
FILE
*
copystream
;
parse_slash_copy
(
args
,
table
,
sizeof
(
table
),
file
,
sizeof
(
file
),
parse_slash_copy
(
args
,
table
,
sizeof
(
table
),
file
,
sizeof
(
file
),
&
from
,
&
syntax_error
);
&
from
,
&
syntax_error
);
if
(
!
syntax_error
)
{
if
(
!
syntax_error
)
{
strcpy
(
query
,
"COPY "
);
strcpy
(
query
,
"COPY "
);
strcat
(
query
,
table
);
strcat
(
query
,
table
);
if
(
from
)
if
(
from
)
strcat
(
query
,
" FROM stdin"
);
strcat
(
query
,
" FROM stdin"
);
else
else
strcat
(
query
,
" TO stdout"
);
strcat
(
query
,
" TO stdout"
);
if
(
from
)
{
if
(
from
)
{
copystream
=
fopen
(
file
,
"r"
);
copystream
=
fopen
(
file
,
"r"
);
}
else
{
}
else
{
copystream
=
fopen
(
file
,
"w"
);
copystream
=
fopen
(
file
,
"w"
);
}
}
if
(
copystream
<
0
)
if
(
copystream
<
0
)
fprintf
(
stderr
,
fprintf
(
stderr
,
"Unable to open file %s which to copy, errno = %s (%d)."
,
"Unable to open file %s which to copy, errno = %s (%d)."
,
from
?
"from"
:
"to"
,
strerror
(
errno
),
errno
);
from
?
"from"
:
"to"
,
strerror
(
errno
),
errno
);
else
{
else
{
bool
success
;
/* The query succeeded at the backend */
bool
success
;
/* The query succeeded at the backend */
SendQuery
(
&
success
,
settings
,
query
,
from
,
!
from
,
copystream
);
SendQuery
(
&
success
,
settings
,
query
,
from
,
!
from
,
copystream
);
fclose
(
copystream
);
fclose
(
copystream
);
if
(
!
settings
->
quiet
)
{
if
(
!
settings
->
quiet
)
{
if
(
success
)
if
(
success
)
fprintf
(
stdout
,
"Successfully copied.
\n
"
);
fprintf
(
stdout
,
"Successfully copied.
\n
"
);
else
else
fprintf
(
stdout
,
"Copy failed.
\n
"
);
fprintf
(
stdout
,
"Copy failed.
\n
"
);
}
}
}
}
}
}
}
}
static
void
static
void
do_connect
(
const
char
*
new_dbname
,
PsqlSettings
*
settings
)
{
do_connect
(
const
char
*
new_dbname
,
PsqlSettings
*
settings
)
{
char
*
dbname
=
PQdb
(
settings
->
db
);
char
*
dbname
=
PQdb
(
settings
->
db
);
if
(
!
new_dbname
)
if
(
!
new_dbname
)
fprintf
(
stderr
,
"
\\
connect must be followed by a database name
\n
"
);
fprintf
(
stderr
,
"
\\
connect must be followed by a database name
\n
"
);
else
{
else
{
PGconn
*
olddb
=
settings
->
db
;
PGconn
*
olddb
=
settings
->
db
;
printf
(
"closing connection to database: %s
\n
"
,
dbname
);
printf
(
"closing connection to database: %s
\n
"
,
dbname
);
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
NULL
,
NULL
,
new_dbname
);
NULL
,
NULL
,
new_dbname
);
printf
(
"connecting to new database: %s
\n
"
,
new_dbname
);
printf
(
"connecting to new database: %s
\n
"
,
new_dbname
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
"%s
\n
"
,
PQerrorMessage
(
settings
->
db
));
fprintf
(
stderr
,
"%s
\n
"
,
PQerrorMessage
(
settings
->
db
));
printf
(
"reconnecting to %s
\n
"
,
dbname
);
printf
(
"reconnecting to %s
\n
"
,
dbname
);
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
NULL
,
NULL
,
dbname
);
NULL
,
NULL
,
dbname
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
fprintf
(
stderr
,
"could not reconnect to %s. exiting
\n
"
,
dbname
);
"could not reconnect to %s. exiting
\n
"
,
dbname
);
exit
(
2
);
exit
(
2
);
}
}
}
else
{
}
else
{
PQfinish
(
olddb
);
PQfinish
(
olddb
);
free
(
settings
->
prompt
);
free
(
settings
->
prompt
);
settings
->
prompt
=
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
10
);
settings
->
prompt
=
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
10
);
sprintf
(
settings
->
prompt
,
"%s=> "
,
PQdb
(
settings
->
db
));
sprintf
(
settings
->
prompt
,
"%s=> "
,
PQdb
(
settings
->
db
));
}
}
}
}
}
}
static
void
static
void
do_edit
(
const
char
*
filename_arg
,
char
*
query
,
int
*
retcode_p
)
{
do_edit
(
const
char
*
filename_arg
,
char
*
query
,
int
*
status_p
)
{
int
fd
;
int
fd
;
char
tmp
[
64
];
char
tmp
[
64
];
char
*
fname
;
char
*
fname
;
int
cc
;
int
cc
;
const
int
ql
=
strlen
(
query
);
const
int
ql
=
strlen
(
query
);
bool
error
;
bool
error
;
if
(
filename_arg
)
{
if
(
filename_arg
)
{
fname
=
(
char
*
)
filename_arg
;
fname
=
(
char
*
)
filename_arg
;
error
=
false
;
error
=
false
;
}
else
{
}
else
{
sprintf
(
tmp
,
"/tmp/psql.%ld.%ld"
,
(
long
)
geteuid
(),
(
long
)
getpid
());
sprintf
(
tmp
,
"/tmp/psql.%ld.%ld"
,
(
long
)
geteuid
(),
(
long
)
getpid
());
fname
=
tmp
;
fname
=
tmp
;
unlink
(
tmp
);
unlink
(
tmp
);
if
(
ql
>
0
)
{
if
(
ql
>
0
)
{
if
((
fd
=
open
(
tmp
,
O_EXCL
|
O_CREAT
|
O_WRONLY
,
0600
))
==
-
1
)
{
if
((
fd
=
open
(
tmp
,
O_EXCL
|
O_CREAT
|
O_WRONLY
,
0600
))
==
-
1
)
{
perror
(
tmp
);
perror
(
tmp
);
error
=
true
;
error
=
true
;
}
else
{
}
else
{
if
(
query
[
ql
-
1
]
!=
'\n'
)
if
(
query
[
ql
-
1
]
!=
'\n'
)
strcat
(
query
,
"
\n
"
);
strcat
(
query
,
"
\n
"
);
if
(
write
(
fd
,
query
,
ql
)
!=
ql
)
{
if
(
write
(
fd
,
query
,
ql
)
!=
ql
)
{
perror
(
tmp
);
perror
(
tmp
);
close
(
fd
);
close
(
fd
);
unlink
(
tmp
);
unlink
(
tmp
);
error
=
true
;
error
=
true
;
}
else
error
=
false
;
}
else
close
(
fd
);
error
=
false
;
}
close
(
fd
);
}
else
error
=
false
;
}
}
else
error
=
false
;
}
}
if
(
error
)
*
retcode_p
=
1
;
if
(
error
)
*
status_p
=
1
;
else
{
else
{
editFile
(
fname
);
editFile
(
fname
);
if
((
fd
=
open
(
fname
,
O_RDONLY
))
==-
1
)
{
if
((
fd
=
open
(
fname
,
O_RDONLY
))
==
-
1
)
{
perror
(
fname
);
perror
(
fname
);
if
(
!
filename_arg
)
if
(
!
filename_arg
)
unlink
(
fname
);
unlink
(
fname
);
*
retcode_p
=
1
;
*
status_p
=
1
;
}
else
{
}
else
{
if
((
cc
=
read
(
fd
,
query
,
MAX_QUERY_BUFFER
))
==-
1
)
{
if
((
cc
=
read
(
fd
,
query
,
MAX_QUERY_BUFFER
))
==
-
1
)
{
perror
(
fname
);
perror
(
fname
);
close
(
fd
);
close
(
fd
);
if
(
!
filename_arg
)
if
(
!
filename_arg
)
unlink
(
fname
);
unlink
(
fname
);
*
retcode_p
=
1
;
*
status_p
=
1
;
}
else
{
}
else
{
query
[
cc
]
=
'\0'
;
query
[
cc
]
=
'\0'
;
close
(
fd
);
close
(
fd
);
if
(
!
filename_arg
)
if
(
!
filename_arg
)
unlink
(
fname
);
unlink
(
fname
);
rightTrim
(
query
);
rightTrim
(
query
);
if
(
query
[
strlen
(
query
)
-
1
]
==
';'
)
*
retcode_p
=
0
;
*
status_p
=
3
;
else
*
retcode_p
=
1
;
}
}
}
}
}
}
}
}
static
void
static
void
do_help
(
const
char
*
topic
)
{
do_help
(
const
char
*
topic
)
{
if
(
!
topic
)
{
if
(
!
topic
)
{
char
left_center_right
;
/* Which column we're displaying */
char
left_center_right
;
/* Which column we're
int
i
;
/* Index into QL_HELP[] */
* displaying */
int
i
;
/* Index into QL_HELP[] */
printf
(
"type
\\
h <cmd> where <cmd> is one of the following:
\n
"
);
printf
(
"type
\\
h <cmd> where <cmd> is one of the following:
\n
"
);
left_center_right
=
'L'
;
/* Start with left column */
i
=
0
;
left_center_right
=
'L'
;
/* Start with left column */
while
(
QL_HELP
[
i
].
cmd
!=
NULL
)
{
i
=
0
;
switch
(
left_center_right
)
{
while
(
QL_HELP
[
i
].
cmd
!=
NULL
)
{
case
'L'
:
switch
(
left_center_right
)
{
printf
(
" %-25s"
,
QL_HELP
[
i
].
cmd
);
case
'L'
:
left_center_right
=
'C'
;
printf
(
" %-25s"
,
QL_HELP
[
i
].
cmd
);
break
;
left_center_right
=
'C'
;
case
'C'
:
break
;
printf
(
"%-25s"
,
QL_HELP
[
i
].
cmd
);
case
'C'
:
left_center_right
=
'R'
;
printf
(
"%-25s"
,
QL_HELP
[
i
].
cmd
);
break
;
left_center_right
=
'R'
;
case
'R'
:
break
;
printf
(
"%-25s
\n
"
,
QL_HELP
[
i
].
cmd
);
case
'R'
:
left_center_right
=
'L'
;
printf
(
"%-25s
\n
"
,
QL_HELP
[
i
].
cmd
);
break
;
left_center_right
=
'L'
;
};
break
;
i
++
;
};
}
i
++
;
if
(
left_center_right
!=
'L'
)
puts
(
"
\n
"
);
}
printf
(
"type
\\
h * for a complete description of all commands
\n
"
);
if
(
left_center_right
!=
'L'
)
puts
(
"
\n
"
);
printf
(
"type
\\
h * for a complete description of all commands
\n
"
);
}
else
{
}
else
{
int
i
;
/* Index into QL_HELP[] */
int
i
;
/* Index into QL_HELP[] */
bool
help_found
;
/* We found the help he asked for */
bool
help_found
;
/* We found the help he asked for */
help_found
=
false
;
/* Haven't found it yet */
help_found
=
false
;
/* Haven't found it yet */
for
(
i
=
0
;
QL_HELP
[
i
].
cmd
;
i
++
)
{
for
(
i
=
0
;
QL_HELP
[
i
].
cmd
;
i
++
)
{
if
(
strcmp
(
QL_HELP
[
i
].
cmd
,
topic
)
==
0
||
if
(
strcmp
(
QL_HELP
[
i
].
cmd
,
topic
)
==
0
||
strcmp
(
topic
,
"*"
)
==
0
)
{
strcmp
(
topic
,
"*"
)
==
0
)
{
help_found
=
true
;
help_found
=
true
;
printf
(
"Command: %s
\n
"
,
QL_HELP
[
i
].
cmd
);
printf
(
"Command: %s
\n
"
,
QL_HELP
[
i
].
cmd
);
printf
(
"Description: %s
\n
"
,
QL_HELP
[
i
].
help
);
printf
(
"Description: %s
\n
"
,
QL_HELP
[
i
].
help
);
printf
(
"Syntax:
\n
"
);
printf
(
"Syntax:
\n
"
);
printf
(
"%s
\n
"
,
QL_HELP
[
i
].
syntax
);
printf
(
"%s
\n
"
,
QL_HELP
[
i
].
syntax
);
printf
(
"
\n
"
);
printf
(
"
\n
"
);
}
}
}
}
if
(
!
help_found
)
if
(
!
help_found
)
printf
(
"command not found, "
printf
(
"command not found, "
"try
\\
h with no arguments to see available help
\n
"
);
"try
\\
h with no arguments to see available help
\n
"
);
}
}
}
}
static
void
static
void
do_shell
(
const
char
*
command
)
{
do_shell
(
const
char
*
command
)
{
if
(
!
command
)
{
if
(
!
command
)
{
char
*
sys
;
char
*
sys
;
char
*
shellName
;
char
*
shellName
;
shellName
=
getenv
(
"SHELL"
);
shellName
=
getenv
(
"SHELL"
);
if
(
shellName
==
NULL
)
if
(
shellName
==
NULL
)
shellName
=
DEFAULT_SHELL
;
shellName
=
DEFAULT_SHELL
;
sys
=
malloc
(
strlen
(
shellName
)
+
16
);
sys
=
malloc
(
strlen
(
shellName
)
+
16
);
if
(
!
sys
)
{
if
(
!
sys
)
{
perror
(
"malloc"
);
perror
(
"malloc"
);
exit
(
1
);
exit
(
1
);
}
}
sprintf
(
sys
,
"exec %s"
,
shellName
);
sprintf
(
sys
,
"exec %s"
,
shellName
);
system
(
sys
);
system
(
sys
);
free
(
sys
);
free
(
sys
);
}
else
system
(
command
);
}
else
system
(
command
);
}
}
/*
/*
HandleSlashCmds:
* HandleSlashCmds:
*
Handles all the different commands that start with \
* Handles all the different commands that start with \ db_ptr is a pointer to
db_ptr is a pointer to the TgDb* structure
* the TgDb* structure line is the current input line prompt_ptr is a pointer
line is the current input line
* to the prompt string, a pointer is used because the prompt can be used
prompt_ptr is a pointer to the prompt string,
* with a connection to a new database returns a status: 0 - send currently
a pointer is used because the prompt can be used with
* constructed query to backend (i.e. we got a \g) 1 - skip processing of
a connection to a new database
* this line, continue building up query 2 - terminate processing of this
returns a status:
* query entirely, 3 - new query supplied by edit
0 - send currently constructed query to backend (i.e. we got a \g)
*/
1 - skip processing of this line, continue building up query
2 - terminate processing of this query entirely
*/
int
int
HandleSlashCmds
(
PsqlSettings
*
settings
,
HandleSlashCmds
(
PsqlSettings
*
settings
,
char
*
line
,
char
*
line
,
char
*
query
)
char
*
query
)
{
{
int
status
=
1
;
int
status
=
1
;
char
*
optarg
;
char
*
optarg
;
/* Pointer inside the <cmd> string to the argument of the slash
/*
command, assuming it is a one-character slash command. If it's
* Pointer inside the <cmd> string to the argument of the slash command,
not a one-character command, this is meaningless.
* assuming it is a one-character slash command. If it's not a
*/
* one-character command, this is meaningless.
char
*
optarg2
;
*/
/* Pointer inside the <cmd> string to the argument of the slash
char
*
optarg2
;
command assuming it's not a one-character command. If it's a
/*
one-character command, this is meaningless.
* Pointer inside the <cmd> string to the argument of the slash command
*/
* assuming it's not a one-character command. If it's a one-character
char
*
cmd
;
* command, this is meaningless.
/* String: value of the slash command, less the slash and with escape
*/
sequences decoded.
char
*
cmd
;
*/
/*
int
blank_loc
;
* String: value of the slash command, less the slash and with escape
* sequences decoded.
*/
int
blank_loc
;
/* Offset within <cmd> of first blank */
/* Offset within <cmd> of first blank */
cmd
=
malloc
(
strlen
(
line
));
/* unescaping better not make string grow. */
cmd
=
malloc
(
strlen
(
line
));
/* unescaping better not make string grow. */
unescape
(
cmd
,
line
+
1
);
/* sets cmd string */
unescape
(
cmd
,
line
+
1
);
/* sets cmd string */
/* Originally, there were just single character commands. Now,
/*
we define some longer, friendly commands, but we have to keep
* Originally, there were just single character commands. Now, we define
the old single character commands too. \c used to be what
* some longer, friendly commands, but we have to keep the old single
\connect is now. Complicating matters is the fact that with
* character commands too. \c used to be what \connect is now.
the single-character commands, you can start the argument
* Complicating matters is the fact that with the single-character
right after the single character, so "\copy" would mean
* commands, you can start the argument right after the single character,
"connect to database named 'opy'".
* so "\copy" would mean
"connect to database named 'opy'".
*/
*/
if
(
strlen
(
cmd
)
>
1
)
optarg
=
cmd
+
1
+
strspn
(
cmd
+
1
,
"
\t
"
);
if
(
strlen
(
cmd
)
>
1
)
else
optarg
=
NULL
;
optarg
=
cmd
+
1
+
strspn
(
cmd
+
1
,
"
\t
"
);
blank_loc
=
strcspn
(
cmd
,
"
\t
"
);
if
(
blank_loc
==
0
)
optarg2
=
NULL
;
else
optarg2
=
cmd
+
blank_loc
+
strspn
(
cmd
+
blank_loc
,
"
\t
"
);
switch
(
cmd
[
0
])
{
case
'a'
:
/* toggles to align fields on output */
toggle
(
settings
,
&
settings
->
opt
.
align
,
"field alignment"
);
break
;
case
'C'
:
/* define new caption */
if
(
settings
->
opt
.
caption
)
free
(
settings
->
opt
.
caption
);
if
(
!
optarg
)
settings
->
opt
.
caption
=
NULL
;
else
else
if
(
!
(
settings
->
opt
.
caption
=
strdup
(
optarg
)))
optarg
=
NULL
;
{
perror
(
"malloc"
);
blank_loc
=
strcspn
(
cmd
,
"
\t
"
);
exit
(
1
);
if
(
blank_loc
==
0
)
}
optarg2
=
NULL
;
break
;
else
case
'c'
:
{
optarg2
=
cmd
+
blank_loc
+
strspn
(
cmd
+
blank_loc
,
"
\t
"
);
if
(
strncmp
(
cmd
,
"copy "
,
strlen
(
"copy "
))
==
0
)
do_copy
(
optarg2
,
settings
);
else
if
(
strncmp
(
cmd
,
"connect "
,
strlen
(
"connect "
))
==
0
)
switch
(
cmd
[
0
])
{
do_connect
(
optarg2
,
settings
);
case
'a'
:
/* toggles to align fields on output */
else
toggle
(
settings
,
&
settings
->
opt
.
align
,
"field alignment"
);
do_connect
(
optarg
,
settings
);
break
;
}
case
'C'
:
/* define new caption */
break
;
if
(
settings
->
opt
.
caption
)
case
'd'
:
/* \d describe tables or columns in a table */
free
(
settings
->
opt
.
caption
);
if
(
!
optarg
)
{
if
(
!
optarg
)
tableList
(
settings
,
0
);
settings
->
opt
.
caption
=
NULL
;
break
;
else
if
(
!
(
settings
->
opt
.
caption
=
strdup
(
optarg
)))
{
}
perror
(
"malloc"
);
if
(
strcmp
(
optarg
,
"*"
)
==
0
)
{
exit
(
1
);
tableList
(
settings
,
0
);
}
tableList
(
settings
,
1
);
break
;
}
case
'c'
:{
else
{
if
(
strncmp
(
cmd
,
"copy "
,
strlen
(
"copy "
))
==
0
)
tableDesc
(
settings
,
optarg
);
do_copy
(
optarg2
,
settings
);
}
else
if
(
strncmp
(
cmd
,
"connect "
,
strlen
(
"connect "
))
==
0
)
break
;
do_connect
(
optarg2
,
settings
);
case
'e'
:
/* edit */
else
{
do_connect
(
optarg
,
settings
);
do_edit
(
optarg
,
query
,
&
status
);
}
break
;
break
;
}
case
'd'
:
/* \d describe tables or columns in a table */
if
(
!
optarg
)
{
tableList
(
settings
,
0
);
break
;
}
if
(
strcmp
(
optarg
,
"*"
)
==
0
)
{
tableList
(
settings
,
0
);
tableList
(
settings
,
1
);
}
else
{
tableDesc
(
settings
,
optarg
);
}
break
;
case
'e'
:
/* edit */
{
do_edit
(
optarg
,
query
,
&
status
);
break
;
}
case
'E'
:
case
'E'
:
{
{
FILE
*
fd
;
FILE
*
fd
;
static
char
*
lastfile
;
static
char
*
lastfile
;
struct
stat
st
,
st2
;
struct
stat
st
,
st2
;
if
(
optarg
)
if
(
optarg
)
{
{
if
(
lastfile
)
if
(
lastfile
)
free
(
lastfile
);
free
(
lastfile
);
lastfile
=
malloc
(
strlen
(
optarg
+
1
));
lastfile
=
malloc
(
strlen
(
optarg
+
1
));
if
(
!
lastfile
)
{
if
(
!
lastfile
)
perror
(
"malloc"
);
{
exit
(
1
);
perror
(
"malloc"
);
}
exit
(
1
);
strcpy
(
lastfile
,
optarg
);
}
}
else
if
(
!
lastfile
)
{
strcpy
(
lastfile
,
optarg
);
fprintf
(
stderr
,
"
\\
r must be followed by a file name initially
\n
"
);
}
else
if
(
!
lastfile
)
break
;
{
}
fprintf
(
stderr
,
"
\\
r must be followed by a file name initially
\n
"
);
stat
(
lastfile
,
&
st
);
break
;
editFile
(
lastfile
);
}
if
((
stat
(
lastfile
,
&
st2
)
==
-
1
)
||
((
fd
=
fopen
(
lastfile
,
"r"
))
==
NULL
))
{
stat
(
lastfile
,
&
st
);
perror
(
lastfile
);
editFile
(
lastfile
);
break
;
if
((
stat
(
lastfile
,
&
st2
)
==
-
1
)
||
((
fd
=
fopen
(
lastfile
,
"r"
))
==
NULL
))
}
{
if
(
st2
.
st_mtime
==
st
.
st_mtime
)
{
perror
(
lastfile
);
if
(
!
settings
->
quiet
)
break
;
fprintf
(
stderr
,
"warning: %s not modified. query not executed
\n
"
,
lastfile
);
}
fclose
(
fd
);
if
(
st2
.
st_mtime
==
st
.
st_mtime
)
break
;
{
}
if
(
!
settings
->
quiet
)
MainLoop
(
settings
,
fd
);
fprintf
(
stderr
,
"warning: %s not modified. query not executed
\n
"
,
lastfile
);
fclose
(
fd
);
fclose
(
fd
);
break
;
break
;
}
}
MainLoop
(
settings
,
fd
);
fclose
(
fd
);
break
;
}
case
'f'
:
case
'f'
:
{
{
char
*
fs
=
DEFAULT_FIELD_SEP
;
char
*
fs
=
DEFAULT_FIELD_SEP
;
if
(
optarg
)
if
(
optarg
)
fs
=
optarg
;
fs
=
optarg
;
if
(
settings
->
opt
.
fieldSep
);
if
(
settings
->
opt
.
fieldSep
);
free
(
settings
->
opt
.
fieldSep
);
free
(
settings
->
opt
.
fieldSep
);
if
(
!
(
settings
->
opt
.
fieldSep
=
strdup
(
fs
)))
if
(
!
(
settings
->
opt
.
fieldSep
=
strdup
(
fs
)))
{
{
perror
(
"malloc"
);
perror
(
"malloc"
);
exit
(
1
);
exit
(
1
);
}
}
if
(
!
settings
->
quiet
)
if
(
!
settings
->
quiet
)
fprintf
(
stderr
,
"field separater changed to '%s'
\n
"
,
settings
->
opt
.
fieldSep
);
fprintf
(
stderr
,
"field separater changed to '%s'
\n
"
,
settings
->
opt
.
fieldSep
);
break
;
break
;
}
}
case
'g'
:
/* \g means send query */
case
'g'
:
/* \g means send query */
settings
->
gfname
=
optarg
;
settings
->
gfname
=
optarg
;
status
=
0
;
status
=
0
;
break
;
break
;
case
'h'
:
/* help */
case
'h'
:
/* help */
{
{
do_help
(
optarg
);
do_help
(
optarg
);
break
;
break
;
}
}
case
'i'
:
/* \i is include file */
case
'i'
:
/* \i is include file */
{
{
FILE
*
fd
;
FILE
*
fd
;
if
(
!
optarg
)
{
if
(
!
optarg
)
{
fprintf
(
stderr
,
"
\\
i must be followed by a file name
\n
"
);
fprintf
(
stderr
,
"
\\
i must be followed by a file name
\n
"
);
break
;
break
;
}
}
if
((
fd
=
fopen
(
optarg
,
"r"
))
==
NULL
)
{
fprintf
(
stderr
,
"file named %s could not be opened
\n
"
,
optarg
);
if
((
fd
=
fopen
(
optarg
,
"r"
))
==
NULL
)
break
;
{
}
fprintf
(
stderr
,
"file named %s could not be opened
\n
"
,
optarg
);
MainLoop
(
settings
,
fd
);
break
;
fclose
(
fd
);
}
break
;
MainLoop
(
settings
,
fd
);
}
fclose
(
fd
);
case
'l'
:
/* \l is list database */
break
;
listAllDbs
(
settings
);
}
break
;
case
'l'
:
/* \l is list database */
listAllDbs
(
settings
);
break
;
case
'H'
:
case
'H'
:
if
(
toggle
(
settings
,
&
settings
->
opt
.
html3
,
"HTML3.0 tabular output"
))
if
(
toggle
(
settings
,
&
settings
->
opt
.
html3
,
"HTML3.0 tabular output"
))
settings
->
opt
.
standard
=
0
;
settings
->
opt
.
standard
=
0
;
break
;
break
;
case
'o'
:
case
'o'
:
setFout
(
settings
,
optarg
);
setFout
(
settings
,
optarg
);
break
;
break
;
case
'p'
:
case
'p'
:
if
(
query
)
if
(
query
)
{
{
fputs
(
query
,
stdout
);
fputs
(
query
,
stdout
);
fputc
(
'\n'
,
stdout
);
fputc
(
'\n'
,
stdout
);
}
}
break
;
break
;
case
'q'
:
/* \q is quit */
case
'q'
:
/* \q is quit */
status
=
2
;
status
=
2
;
break
;
break
;
case
'r'
:
/* reset(clear) the buffer */
case
'r'
:
/* reset(clear) the buffer */
query
[
0
]
=
'\0'
;
query
[
0
]
=
'\0'
;
if
(
!
settings
->
quiet
)
if
(
!
settings
->
quiet
)
fprintf
(
stderr
,
"buffer reset(cleared)
\n
"
);
fprintf
(
stderr
,
"buffer reset(cleared)
\n
"
);
break
;
break
;
case
's'
:
/* \s is save history to a file */
case
's'
:
/* \s is save history to a file */
if
(
!
optarg
)
if
(
!
optarg
)
optarg
=
"/dev/tty"
;
optarg
=
"/dev/tty"
;
if
(
write_history
(
optarg
)
!=
0
)
if
(
write_history
(
optarg
)
!=
0
)
fprintf
(
stderr
,
"cannot write history to %s
\n
"
,
optarg
);
fprintf
(
stderr
,
"cannot write history to %s
\n
"
,
optarg
);
break
;
break
;
case
'm'
:
/* monitor like type-setting */
case
'm'
:
/* monitor like type-setting */
if
(
toggle
(
settings
,
&
settings
->
opt
.
standard
,
"standard SQL separaters and padding"
))
{
if
(
toggle
(
settings
,
&
settings
->
opt
.
standard
,
"standard SQL separaters and padding"
))
settings
->
opt
.
html3
=
settings
->
opt
.
expanded
=
0
;
{
settings
->
opt
.
align
=
settings
->
opt
.
header
=
1
;
settings
->
opt
.
html3
=
settings
->
opt
.
expanded
=
0
;
free
(
settings
->
opt
.
fieldSep
);
settings
->
opt
.
align
=
settings
->
opt
.
header
=
1
;
settings
->
opt
.
fieldSep
=
strdup
(
"|"
);
free
(
settings
->
opt
.
fieldSep
);
if
(
!
settings
->
quiet
)
settings
->
opt
.
fieldSep
=
strdup
(
"|"
);
fprintf
(
stderr
,
"field separater changed to '%s'
\n
"
,
settings
->
opt
.
fieldSep
);
if
(
!
settings
->
quiet
)
}
else
{
fprintf
(
stderr
,
"field separater changed to '%s'
\n
"
,
settings
->
opt
.
fieldSep
);
free
(
settings
->
opt
.
fieldSep
);
}
else
settings
->
opt
.
fieldSep
=
strdup
(
DEFAULT_FIELD_SEP
);
{
if
(
!
settings
->
quiet
)
free
(
settings
->
opt
.
fieldSep
);
fprintf
(
stderr
,
"field separater changed to '%s'
\n
"
,
settings
->
opt
.
fieldSep
);
settings
->
opt
.
fieldSep
=
strdup
(
DEFAULT_FIELD_SEP
);
}
if
(
!
settings
->
quiet
)
break
;
fprintf
(
stderr
,
"field separater changed to '%s'
\n
"
,
settings
->
opt
.
fieldSep
);
case
't'
:
/* toggle headers */
}
toggle
(
settings
,
&
settings
->
opt
.
header
,
"output headings and row count"
);
break
;
break
;
case
't'
:
/* toggle headers */
case
'T'
:
/* define html <table ...> option */
toggle
(
settings
,
&
settings
->
opt
.
header
,
"output headings and row count"
);
if
(
settings
->
opt
.
tableOpt
)
break
;
free
(
settings
->
opt
.
tableOpt
);
case
'T'
:
/* define html <table ...> option */
if
(
!
optarg
)
if
(
settings
->
opt
.
tableOpt
)
settings
->
opt
.
tableOpt
=
NULL
;
free
(
settings
->
opt
.
tableOpt
);
else
if
(
!
(
settings
->
opt
.
tableOpt
=
strdup
(
optarg
)))
{
if
(
!
optarg
)
perror
(
"malloc"
);
settings
->
opt
.
tableOpt
=
NULL
;
exit
(
1
);
else
}
if
(
!
(
settings
->
opt
.
tableOpt
=
strdup
(
optarg
)))
break
;
{
perror
(
"malloc"
);
exit
(
1
);
}
break
;
case
'x'
:
case
'x'
:
toggle
(
settings
,
&
settings
->
opt
.
expanded
,
"expanded table representation"
);
toggle
(
settings
,
&
settings
->
opt
.
expanded
,
"expanded table representation"
);
break
;
break
;
case
'!'
:
case
'!'
:
do_shell
(
optarg
);
do_shell
(
optarg
);
break
;
break
;
default:
default:
case
'?'
:
/* \? is help */
case
'?'
:
/* \? is help */
slashUsage
(
settings
);
slashUsage
(
settings
);
break
;
break
;
}
}
free
(
cmd
);
free
(
cmd
);
return
status
;
return
status
;
}
}
/*
/*
MainLoop: main processing loop for reading lines of input
* MainLoop: main processing loop for reading lines of input and sending them
and sending them
to the backend
*
to the backend
*
this loop is re-entrant. May be called by \i command
* this loop is re-entrant. May be called by \i command which reads input from
which reads input from
a file
*
a file
*
*db_ptr must be initialized and set
*
db_ptr must be initialized and set
*/
*/
int
int
MainLoop
(
PsqlSettings
*
settings
,
FILE
*
source
)
MainLoop
(
PsqlSettings
*
settings
,
FILE
*
source
)
{
{
char
*
line
;
/* line of input */
char
*
line
;
/* line of input */
int
len
;
/* length of the line */
int
len
;
/* length of the line */
char
query
[
MAX_QUERY_BUFFER
];
/* multi-line query storage */
char
query
[
MAX_QUERY_BUFFER
];
/* multi-line query storage */
int
exitStatus
=
0
;
int
successResult
=
1
;
int
slashCmdStatus
=
0
;
int
slashCmdStatus
=
0
;
/* slashCmdStatus can be:
/*
0 - send currently constructed query to backend (i.e. we got a \g)
* slashCmdStatus can be: 0 - send currently constructed query to backend
1 - skip processing of this line, continue building up query
* (i.e. we got a \g) 1 - skip processing of this line, continue building
2 - terminate processing of this query entirely
* up query 2 - terminate processing of this query entirely 3 - new query
*/
* supplied by edit
*/
bool
sendQuery
=
0
;
bool
querySent
=
0
;
bool
querySent
=
false
;
bool
interactive
;
bool
interactive
;
READ_ROUTINE
GetNextLine
;
READ_ROUTINE
GetNextLine
;
bool
connected
=
1
;
bool
eof
=
0
;
/* We are connected to the backend (last time we looked) */
/* We've reached the end of our command input. */
bool
eof
=
0
;
bool
success
;
/* We've reached the end of our command input. */
bool
in_quote
;
bool
was_bslash
;
/* backslash */
bool
was_dash
;
int
paren_level
;
char
*
query_start
;
interactive
=
((
source
==
stdin
)
&&
!
settings
->
notty
);
interactive
=
((
source
==
stdin
)
&&
!
settings
->
notty
);
#define PROMPT "=> "
#define PROMPT "=> "
if
(
interactive
)
{
if
(
interactive
)
{
if
(
settings
->
prompt
)
if
(
settings
->
prompt
)
free
(
settings
->
prompt
);
free
(
settings
->
prompt
);
settings
->
prompt
=
settings
->
prompt
=
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
strlen
(
PROMPT
)
+
1
);
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
strlen
(
PROMPT
)
+
1
);
if
(
settings
->
quiet
)
if
(
settings
->
quiet
)
settings
->
prompt
[
0
]
=
'\0'
;
settings
->
prompt
[
0
]
=
'\0'
;
else
else
sprintf
(
settings
->
prompt
,
"%s%s"
,
PQdb
(
settings
->
db
),
PROMPT
);
sprintf
(
settings
->
prompt
,
"%s%s"
,
PQdb
(
settings
->
db
),
PROMPT
);
if
(
settings
->
useReadline
)
{
if
(
settings
->
useReadline
)
{
using_history
();
using_history
();
GetNextLine
=
gets_readline
;
GetNextLine
=
gets_readline
;
}
else
GetNextLine
=
gets_noreadline
;
}
else
}
else
GetNextLine
=
gets_fromFile
;
GetNextLine
=
gets_noreadline
;
}
else
GetNextLine
=
gets_fromFile
;
query
[
0
]
=
'\0'
;
query
[
0
]
=
'\0'
;
in_quote
=
false
;
/* main loop for getting queries and executing them */
paren_level
=
0
;
while
(
connected
&&
!
eof
)
{
slashCmdStatus
=
-
1
;
/* set default */
line
=
GetNextLine
(
settings
->
prompt
,
source
);
if
(
line
==
NULL
)
{
/* No more input. Time to quit */
printf
(
"EOF
\n
"
);
/* Goes on prompt line */
eof
=
true
;
}
else
{
exitStatus
=
0
;
line
=
rightTrim
(
line
);
/* remove whitespaces on the right, incl. \n's */
if
(
line
[
0
]
==
'\0'
)
{
free
(
line
);
continue
;
}
/* filter out comment lines that begin with --,
this could be incorrect if -- is part of a quoted string.
But we won't go through the trouble of detecting that.
If you have -- in your quoted string, be careful and don't
start a line with it
*/
if
(
line
[
0
]
==
'-'
&&
line
[
1
]
==
'-'
)
{
if
(
settings
->
singleStep
)
/* in single step mode, show comments */
fprintf
(
stdout
,
"%s
\n
"
,
line
);
free
(
line
);
continue
;
}
if
(
line
[
0
]
!=
'\\'
&&
querySent
)
{
query
[
0
]
=
'\0'
;
querySent
=
0
;
}
len
=
strlen
(
line
);
if
(
interactive
&&
settings
->
useReadline
)
add_history
(
line
);
/* save non-empty lines in history */
/* do the query immediately if we are doing single line queries
or if the last character is a semicolon
*/
sendQuery
=
settings
->
singleLineMode
||
(
line
[
len
-
1
]
==
';'
)
;
/* normally, \ commands have to be start the line,
but for backwards compatibility with monitor,
check for \g at the end of line */
if
(
len
>
2
&&
!
sendQuery
)
{
if
(
line
[
len
-
1
]
==
'g'
&&
line
[
len
-
2
]
==
'\\'
)
{
sendQuery
=
1
;
line
[
len
-
2
]
=
'\0'
;
}
}
/* slash commands have to be on their own line */
if
(
line
[
0
]
==
'\\'
)
{
slashCmdStatus
=
HandleSlashCmds
(
settings
,
line
,
query
);
if
(
slashCmdStatus
==
1
)
{
free
(
line
);
continue
;
}
if
(
slashCmdStatus
==
2
)
{
free
(
line
);
break
;
}
if
(
slashCmdStatus
==
0
)
sendQuery
=
1
;
}
else
if
(
strlen
(
query
)
+
len
>
MAX_QUERY_BUFFER
)
{
fprintf
(
stderr
,
"query buffer max length of %d exceeded
\n
"
,
MAX_QUERY_BUFFER
);
fprintf
(
stderr
,
"query line ignored
\n
"
);
}
else
if
(
query
[
0
]
!=
'\0'
)
{
strcat
(
query
,
"
\n
"
);
strcat
(
query
,
line
);
}
else
strcpy
(
query
,
line
);
if
(
sendQuery
&&
query
[
0
]
!=
'\0'
)
{
/* echo the line read from the file,
unless we are in single_step mode, because single_step mode
will echo anyway
*/
bool
success
;
/* The query succeeded at the backend */
if
(
!
interactive
&&
!
settings
->
singleStep
&&
!
settings
->
quiet
)
fprintf
(
stderr
,
"%s
\n
"
,
query
);
SendQuery
(
&
success
,
settings
,
query
,
false
,
false
,
0
);
exitStatus
=
success
?
0
:
1
;
querySent
=
1
;
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
connected
=
0
;
fprintf
(
stderr
,
"We have lost the connection to the backend, so "
"further processing is impossible. "
"Terminating.
\n
"
);
}
}
free
(
line
);
/* free storage malloc'd by GetNextLine */
}
}
/* while */
return
exitStatus
;
}
/* main loop for getting queries and executing them */
while
(
!
eof
)
{
if
(
slashCmdStatus
==
3
)
{
line
=
strdup
(
query
);
query
[
0
]
=
'\0'
;
}
else
{
line
=
GetNextLine
(
settings
->
prompt
,
source
);
if
(
interactive
&&
settings
->
useReadline
&&
line
!=
NULL
)
add_history
(
line
);
/* save non-empty lines in history */
}
query_start
=
line
;
if
(
line
==
NULL
)
{
/* No more input. Time to quit */
printf
(
"EOF
\n
"
);
/* Goes on prompt line */
eof
=
true
;
}
else
{
if
(
!
interactive
&&
!
settings
->
singleStep
&&
!
settings
->
quiet
)
fprintf
(
stderr
,
"%s
\n
"
,
line
);
/* remove whitespaces on the right, incl. \n's */
line
=
rightTrim
(
line
);
if
(
line
[
0
]
==
'\0'
)
{
free
(
line
);
continue
;
}
len
=
strlen
(
line
);
if
(
settings
->
singleLineMode
)
{
SendQuery
(
&
success
,
settings
,
line
,
false
,
false
,
0
);
successResult
&=
success
;
querySent
=
true
;
}
else
{
int
i
;
was_bslash
=
false
;
was_dash
=
false
;
for
(
i
=
0
;
i
<
len
;
i
++
)
{
if
(
!
in_quote
&&
line
[
i
]
==
'\\'
)
{
char
hold_char
=
line
[
i
];
line
[
i
]
=
'\0'
;
if
(
query_start
[
0
]
!=
'\0'
)
{
if
(
query
[
0
]
!=
'\0'
)
{
strcat
(
query
,
"
\n
"
);
strcat
(
query
,
query_start
);
}
else
strcpy
(
query
,
query_start
);
}
line
[
i
]
=
hold_char
;
query_start
=
line
+
i
;
break
;
/* handle command */
}
if
(
querySent
&&
!
isspace
(
line
[
i
]))
{
query
[
0
]
=
'\0'
;
querySent
=
false
;
}
if
(
!
in_quote
&&
was_dash
&&
line
[
i
]
==
'-'
)
{
/* print comment at top of query */
if
(
settings
->
singleStep
)
fprintf
(
stdout
,
"%s
\n
"
,
line
+
i
-
1
);
line
[
i
-
1
]
=
'\0'
;
/* remove comment */
break
;
}
was_dash
=
false
;
if
(
!
in_quote
&&
!
paren_level
&&
line
[
i
]
==
';'
)
{
char
hold_char
=
line
[
i
+
1
];
line
[
i
+
1
]
=
'\0'
;
if
(
query_start
[
0
]
!=
'\0'
)
{
if
(
query
[
0
]
!=
'\0'
)
{
strcat
(
query
,
"
\n
"
);
strcat
(
query
,
query_start
);
}
else
strcpy
(
query
,
query_start
);
}
SendQuery
(
&
success
,
settings
,
query
,
false
,
false
,
0
);
successResult
&=
success
;
line
[
i
+
1
]
=
hold_char
;
query_start
=
line
+
i
+
1
;
querySent
=
true
;
}
if
(
was_bslash
)
was_bslash
=
false
;
else
if
(
line
[
i
]
==
'\\'
)
was_bslash
=
true
;
else
if
(
line
[
i
]
==
'\''
)
in_quote
^=
1
;
else
if
(
!
in_quote
&&
line
[
i
]
==
'('
)
paren_level
++
;
else
if
(
!
in_quote
&&
paren_level
&&
line
[
i
]
==
')'
)
paren_level
--
;
else
if
(
!
in_quote
&&
line
[
i
]
==
'-'
)
was_dash
=
true
;
}
}
slashCmdStatus
=
-
1
;
/* slash commands have to be on their own line */
if
(
!
in_quote
&&
query_start
[
0
]
==
'\\'
)
{
slashCmdStatus
=
HandleSlashCmds
(
settings
,
query_start
,
query
);
if
(
slashCmdStatus
==
1
)
{
free
(
line
);
continue
;
}
if
(
slashCmdStatus
==
2
)
{
free
(
line
);
break
;
}
}
else
if
(
strlen
(
query
)
+
strlen
(
query_start
)
>
MAX_QUERY_BUFFER
)
{
fprintf
(
stderr
,
"query buffer max length of %d exceeded
\n
"
,
MAX_QUERY_BUFFER
);
fprintf
(
stderr
,
"query line ignored
\n
"
);
}
else
{
if
(
query_start
[
0
]
!=
'\0'
)
{
querySent
=
false
;
if
(
query
[
0
]
!=
'\0'
)
{
strcat
(
query
,
"
\n
"
);
strcat
(
query
,
query_start
);
}
else
strcpy
(
query
,
query_start
);
}
}
if
(
slashCmdStatus
==
0
)
{
SendQuery
(
&
success
,
settings
,
query
,
false
,
false
,
0
);
successResult
&=
success
;
querySent
=
true
;
}
free
(
line
);
/* free storage malloc'd by GetNextLine */
}
}
/* while */
return
successResult
;
}
int
int
main
(
int
argc
,
char
**
argv
)
main
(
int
argc
,
char
**
argv
)
{
{
extern
char
*
optarg
;
extern
char
*
optarg
;
extern
int
optind
;
extern
int
optind
;
char
*
dbname
=
NULL
;
char
*
dbname
=
NULL
;
char
*
host
=
NULL
;
char
*
host
=
NULL
;
char
*
port
=
NULL
;
char
*
port
=
NULL
;
char
*
qfilename
=
NULL
;
char
*
qfilename
=
NULL
;
char
errbuf
[
ERROR_MSG_LENGTH
];
char
errbuf
[
ERROR_MSG_LENGTH
];
PsqlSettings
settings
;
PsqlSettings
settings
;
char
*
singleQuery
=
NULL
;
char
*
singleQuery
=
NULL
;
bool
listDatabases
=
0
;
bool
listDatabases
=
0
;
int
exitStatus
=
0
;
int
successResult
=
1
;
bool
singleSlashCmd
=
0
;
bool
singleSlashCmd
=
0
;
int
c
;
int
c
;
memset
(
&
settings
,
0
,
sizeof
settings
);
memset
(
&
settings
,
0
,
sizeof
settings
);
settings
.
opt
.
align
=
1
;
settings
.
opt
.
align
=
1
;
settings
.
opt
.
header
=
1
;
settings
.
opt
.
header
=
1
;
settings
.
queryFout
=
stdout
;
settings
.
queryFout
=
stdout
;
settings
.
opt
.
fieldSep
=
strdup
(
DEFAULT_FIELD_SEP
);
settings
.
opt
.
fieldSep
=
strdup
(
DEFAULT_FIELD_SEP
);
settings
.
opt
.
pager
=
1
;
settings
.
opt
.
pager
=
1
;
if
(
!
isatty
(
0
)
||
!
isatty
(
1
))
if
(
!
isatty
(
0
)
||
!
isatty
(
1
))
settings
.
quiet
=
settings
.
notty
=
1
;
settings
.
quiet
=
settings
.
notty
=
1
;
#ifndef NOREADLINE
#ifndef NOREADLINE
else
else
settings
.
useReadline
=
1
;
settings
.
useReadline
=
1
;
#endif
#endif
while
((
c
=
getopt
(
argc
,
argv
,
"Aa:c:d:ef:F:lh:Hnso:p:qStT:x"
))
!=
EOF
)
{
while
((
c
=
getopt
(
argc
,
argv
,
"Aa:c:d:ef:F:lh:Hnso:p:qStT:x"
))
!=
EOF
)
{
switch
(
c
)
{
switch
(
c
)
{
case
'A'
:
case
'A'
:
settings
.
opt
.
align
=
0
;
settings
.
opt
.
align
=
0
;
break
;
break
;
case
'a'
:
case
'a'
:
fe_setauthsvc
(
optarg
,
errbuf
);
fe_setauthsvc
(
optarg
,
errbuf
);
break
;
break
;
case
'c'
:
case
'c'
:
singleQuery
=
optarg
;
singleQuery
=
optarg
;
if
(
singleQuery
[
0
]
==
'\\'
)
{
if
(
singleQuery
[
0
]
==
'\\'
)
{
singleSlashCmd
=
1
;
singleSlashCmd
=
1
;
}
break
;
case
'd'
:
dbname
=
optarg
;
break
;
case
'e'
:
settings
.
echoQuery
=
1
;
break
;
case
'f'
:
qfilename
=
optarg
;
break
;
case
'F'
:
settings
.
opt
.
fieldSep
=
optarg
;
break
;
case
'l'
:
listDatabases
=
1
;
break
;
case
'h'
:
host
=
optarg
;
break
;
case
'H'
:
settings
.
opt
.
html3
=
1
;
break
;
case
'n'
:
settings
.
useReadline
=
0
;
break
;
case
'o'
:
setFout
(
&
settings
,
optarg
);
break
;
case
'p'
:
port
=
optarg
;
break
;
case
'q'
:
settings
.
quiet
=
1
;
break
;
case
's'
:
settings
.
singleStep
=
1
;
break
;
case
'S'
:
settings
.
singleLineMode
=
1
;
break
;
case
't'
:
settings
.
opt
.
header
=
0
;
break
;
case
'T'
:
settings
.
opt
.
tableOpt
=
optarg
;
break
;
case
'x'
:
settings
.
opt
.
expanded
=
1
;
break
;
default:
usage
(
argv
[
0
]);
break
;
}
}
}
break
;
/* if we still have an argument, use it as the database name */
case
'd'
:
if
(
argc
-
optind
==
1
)
dbname
=
optarg
;
dbname
=
argv
[
optind
];
break
;
case
'e'
:
if
(
listDatabases
)
settings
.
echoQuery
=
1
;
dbname
=
"template1"
;
break
;
case
'f'
:
settings
.
db
=
PQsetdb
(
host
,
port
,
NULL
,
NULL
,
dbname
);
qfilename
=
optarg
;
dbname
=
PQdb
(
settings
.
db
);
break
;
case
'F'
:
if
(
PQstatus
(
settings
.
db
)
==
CONNECTION_BAD
)
{
settings
.
opt
.
fieldSep
=
optarg
;
fprintf
(
stderr
,
"Connection to database '%s' failed.
\n
"
,
dbname
);
break
;
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
.
db
));
case
'l'
:
exit
(
1
);
listDatabases
=
1
;
}
break
;
if
(
listDatabases
)
{
case
'h'
:
exit
(
listAllDbs
(
&
settings
));
host
=
optarg
;
}
break
;
if
(
!
settings
.
quiet
&&
!
singleQuery
&&
!
qfilename
)
{
case
'H'
:
printf
(
"Welcome to the POSTGRES95 interactive sql monitor:
\n
"
);
settings
.
opt
.
html3
=
1
;
printf
(
" Please read the file COPYRIGHT for copyright terms "
break
;
"of POSTGRES95
\n\n
"
);
case
'n'
:
printf
(
" type
\\
? for help on slash commands
\n
"
);
settings
.
useReadline
=
0
;
printf
(
" type
\\
q to quit
\n
"
);
break
;
printf
(
" type
\\
g or terminate with semicolon to execute query
\n
"
);
case
'o'
:
printf
(
" You are currently connected to the database: %s
\n\n
"
,
dbname
);
setFout
(
&
settings
,
optarg
);
break
;
case
'p'
:
port
=
optarg
;
break
;
case
'q'
:
settings
.
quiet
=
1
;
break
;
case
's'
:
settings
.
singleStep
=
1
;
break
;
case
'S'
:
settings
.
singleLineMode
=
1
;
break
;
case
't'
:
settings
.
opt
.
header
=
0
;
break
;
case
'T'
:
settings
.
opt
.
tableOpt
=
optarg
;
break
;
case
'x'
:
settings
.
opt
.
expanded
=
1
;
break
;
default:
usage
(
argv
[
0
]);
break
;
}
}
}
if
(
qfilename
||
singleSlashCmd
)
{
/* if we still have an argument, use it as the database name */
/*
if
(
argc
-
optind
==
1
)
* read in a file full of queries instead of reading in queries
dbname
=
argv
[
optind
];
* interactively
*/
if
(
listDatabases
)
char
*
line
;
dbname
=
"template1"
;
if
(
singleSlashCmd
)
{
settings
.
db
=
PQsetdb
(
host
,
port
,
NULL
,
NULL
,
dbname
);
/* Not really a query, but "Do what I mean, not what I say." */
dbname
=
PQdb
(
settings
.
db
);
line
=
singleQuery
;
}
else
{
if
(
PQstatus
(
settings
.
db
)
==
CONNECTION_BAD
)
{
line
=
malloc
(
strlen
(
qfilename
)
+
5
);
fprintf
(
stderr
,
"Connection to database '%s' failed.
\n
"
,
dbname
);
sprintf
(
line
,
"
\\
i %s"
,
qfilename
);
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
.
db
));
}
exit
(
1
);
HandleSlashCmds
(
&
settings
,
line
,
""
);
}
}
else
{
if
(
listDatabases
)
{
if
(
singleQuery
)
{
exit
(
listAllDbs
(
&
settings
));
bool
success
;
/* The query succeeded at the backend */
}
SendQuery
(
&
success
,
&
settings
,
singleQuery
,
false
,
false
,
0
);
successResult
=
success
;
if
(
!
settings
.
quiet
&&
!
singleQuery
&&
!
qfilename
)
{
}
else
printf
(
"Welcome to the POSTGRES95 interactive sql monitor:
\n
"
);
successResult
=
MainLoop
(
&
settings
,
stdin
);
printf
(
" Please read the file COPYRIGHT for copyright terms "
}
"of POSTGRES95
\n\n
"
);
printf
(
" type
\\
? for help on slash commands
\n
"
);
PQfinish
(
settings
.
db
);
printf
(
" type
\\
q to quit
\n
"
);
printf
(
" type
\\
g or terminate with semicolon to execute query
\n
"
);
return
!
successResult
;
printf
(
" You are currently connected to the database: %s
\n\n
"
,
dbname
);
}
if
(
qfilename
||
singleSlashCmd
)
{
/* read in a file full of queries instead of reading in queries
interactively */
char
*
line
;
if
(
singleSlashCmd
)
{
/* Not really a query, but "Do what I mean, not what I say." */
line
=
singleQuery
;
}
else
{
line
=
malloc
(
strlen
(
qfilename
)
+
5
);
sprintf
(
line
,
"
\\
i %s"
,
qfilename
);
}
HandleSlashCmds
(
&
settings
,
line
,
""
);
}
else
{
if
(
singleQuery
)
{
bool
success
;
/* The query succeeded at the backend */
SendQuery
(
&
success
,
&
settings
,
singleQuery
,
false
,
false
,
0
);
exitStatus
=
success
?
0
:
1
;
}
else
exitStatus
=
MainLoop
(
&
settings
,
stdin
);
}
PQfinish
(
settings
.
db
);
return
exitStatus
;
}
}
#define COPYBUFSIZ 8192
#define COPYBUFSIZ 8192
static
void
static
void
handleCopyOut
(
PGresult
*
res
,
bool
quiet
,
FILE
*
copystream
)
{
handleCopyOut
(
PGresult
*
res
,
bool
quiet
,
FILE
*
copystream
)
bool
copydone
;
{
char
copybuf
[
COPYBUFSIZ
];
bool
copydone
;
int
ret
;
char
copybuf
[
COPYBUFSIZ
];
int
ret
;
copydone
=
false
;
/* Can't be done; haven't started. */
copydone
=
false
;
/* Can't be done; haven't started. */
while
(
!
copydone
)
{
while
(
!
copydone
)
{
ret
=
PQgetline
(
res
->
conn
,
copybuf
,
COPYBUFSIZ
);
ret
=
PQgetline
(
res
->
conn
,
copybuf
,
COPYBUFSIZ
);
if
(
copybuf
[
0
]
==
'\\'
&&
if
(
copybuf
[
0
]
==
'\\'
&&
copybuf
[
1
]
==
'.'
&&
copybuf
[
1
]
==
'.'
&&
copybuf
[
2
]
==
'\0'
)
{
copybuf
[
2
]
==
'\0'
)
{
copydone
=
true
;
/* don't print this... */
copydone
=
true
;
/* don't print this... */
}
else
{
}
else
{
fputs
(
copybuf
,
copystream
);
fputs
(
copybuf
,
copystream
);
switch
(
ret
)
{
switch
(
ret
)
{
case
EOF
:
case
EOF
:
copydone
=
true
;
copydone
=
true
;
/*FALLTHROUGH
*/
/* FALLTHROUGH
*/
case
0
:
case
0
:
fputc
(
'\n'
,
copystream
);
fputc
(
'\n'
,
copystream
);
break
;
break
;
case
1
:
case
1
:
break
;
break
;
}
}
}
}
}
}
fflush
(
copystream
);
fflush
(
copystream
);
PQendcopy
(
res
->
conn
);
PQendcopy
(
res
->
conn
);
...
@@ -1544,89 +1588,85 @@ handleCopyOut(PGresult *res, bool quiet, FILE *copystream) {
...
@@ -1544,89 +1588,85 @@ handleCopyOut(PGresult *res, bool quiet, FILE *copystream) {
static
void
static
void
handleCopyIn
(
PGresult
*
res
,
const
bool
mustprompt
,
FILE
*
copystream
)
{
handleCopyIn
(
PGresult
*
res
,
const
bool
mustprompt
,
FILE
*
copystream
)
bool
copydone
=
false
;
{
bool
firstload
;
bool
copydone
=
false
;
bool
linedone
;
bool
firstload
;
char
copybuf
[
COPYBUFSIZ
];
bool
linedone
;
char
*
s
;
char
copybuf
[
COPYBUFSIZ
];
int
buflen
;
char
*
s
;
int
c
;
int
buflen
;
int
c
;
if
(
mustprompt
)
{
if
(
mustprompt
)
{
fputs
(
"Enter info followed by a newline
\n
"
,
stdout
);
fputs
(
"Enter info followed by a newline
\n
"
,
stdout
);
fputs
(
"End with a backslash and a "
fputs
(
"End with a backslash and a "
"period on a line by itself.
\n
"
,
stdout
);
"period on a line by itself.
\n
"
,
stdout
);
}
}
while
(
!
copydone
)
{
/* for each input line ... */
while
(
!
copydone
)
{
/* for each input line ... */
if
(
mustprompt
)
{
if
(
mustprompt
)
{
fputs
(
">> "
,
stdout
);
fputs
(
">> "
,
stdout
);
fflush
(
stdout
);
fflush
(
stdout
);
}
}
firstload
=
true
;
firstload
=
true
;
linedone
=
false
;
linedone
=
false
;
while
(
!
linedone
)
{
/* for each buffer ... */
while
(
!
linedone
)
{
/* for each buffer ... */
s
=
copybuf
;
s
=
copybuf
;
buflen
=
COPYBUFSIZ
;
buflen
=
COPYBUFSIZ
;
for
(;
buflen
>
1
&&
for
(;
buflen
>
1
&&
!
(
linedone
=
(
c
=
getc
(
copystream
))
==
'\n'
||
c
==
EOF
);
!
(
linedone
=
(
c
=
getc
(
copystream
))
==
'\n'
||
c
==
EOF
);
--
buflen
)
{
--
buflen
)
{
*
s
++
=
c
;
*
s
++
=
c
;
}
}
if
(
c
==
EOF
)
{
if
(
c
==
EOF
)
{
PQputline
(
res
->
conn
,
"
\\
."
);
PQputline
(
res
->
conn
,
"
\\
."
);
copydone
=
true
;
copydone
=
true
;
break
;
break
;
}
}
*
s
=
'\0'
;
*
s
=
'\0'
;
PQputline
(
res
->
conn
,
copybuf
);
PQputline
(
res
->
conn
,
copybuf
);
if
(
firstload
)
{
if
(
firstload
)
{
if
(
!
strcmp
(
copybuf
,
"
\\
."
))
{
if
(
!
strcmp
(
copybuf
,
"
\\
."
))
{
copydone
=
true
;
copydone
=
true
;
}
}
firstload
=
false
;
firstload
=
false
;
}
}
}
}
PQputline
(
res
->
conn
,
"
\n
"
);
PQputline
(
res
->
conn
,
"
\n
"
);
}
}
PQendcopy
(
res
->
conn
);
PQendcopy
(
res
->
conn
);
}
}
/* try to open fname and return a FILE *,
/*
if it fails, use stdout, instead */
* try to open fname and return a FILE *, if it fails, use stdout, instead
*/
FILE
*
FILE
*
setFout
(
PsqlSettings
*
ps
,
char
*
fname
)
setFout
(
PsqlSettings
*
ps
,
char
*
fname
)
{
{
if
(
ps
->
queryFout
&&
ps
->
queryFout
!=
stdout
)
if
(
ps
->
queryFout
&&
ps
->
queryFout
!=
stdout
)
{
{
if
(
ps
->
pipe
)
if
(
ps
->
pipe
)
pclose
(
ps
->
queryFout
);
pclose
(
ps
->
queryFout
);
else
else
fclose
(
ps
->
queryFout
);
fclose
(
ps
->
queryFout
);
}
}
if
(
!
fname
)
if
(
!
fname
)
ps
->
queryFout
=
stdout
;
ps
->
queryFout
=
stdout
;
else
else
{
{
if
(
*
fname
==
'|'
)
{
if
(
*
fname
==
'|'
)
signal
(
SIGPIPE
,
SIG_IGN
);
{
ps
->
queryFout
=
popen
(
fname
+
1
,
"w"
);
signal
(
SIGPIPE
,
SIG_IGN
);
ps
->
pipe
=
1
;
ps
->
queryFout
=
popen
(
fname
+
1
,
"w"
);
}
else
{
ps
->
pipe
=
1
;
ps
->
queryFout
=
fopen
(
fname
,
"w"
);
}
ps
->
pipe
=
0
;
else
}
{
if
(
!
ps
->
queryFout
)
{
ps
->
queryFout
=
fopen
(
fname
,
"w"
);
perror
(
fname
);
ps
->
pipe
=
0
;
ps
->
queryFout
=
stdout
;
}
}
if
(
!
ps
->
queryFout
)
{
perror
(
fname
);
ps
->
queryFout
=
stdout
;
}
}
}
return
ps
->
queryFout
;
return
ps
->
queryFout
;
}
}
src/bin/psql/stringutils.c
View file @
0365c51e
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
* IDENTIFICATION
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.
4 1996/09/16 06:06:17 scrappy
Exp $
* $Header: /cvsroot/pgsql/src/bin/psql/stringutils.c,v 1.
5 1996/11/14 16:08:05 momjian
Exp $
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -19,8 +19,11 @@
...
@@ -19,8 +19,11 @@
/* all routines assume null-terminated strings! */
/* all routines assume null-terminated strings! */
/* removes whitespaces from the left, right and both sides of a string */
/* The following routines remove whitespaces from the left, right
and both sides of a string */
/* MODIFIES the string passed in and returns the head of it */
/* MODIFIES the string passed in and returns the head of it */
char
*
leftTrim
(
char
*
s
)
char
*
leftTrim
(
char
*
s
)
{
{
char
*
s2
=
s
;
char
*
s2
=
s
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment