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
7870c5a0
Commit
7870c5a0
authored
Nov 04, 1996
by
Bryan Henderson
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add frontend \copy command.
parent
434201d8
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
973 additions
and
771 deletions
+973
-771
src/bin/psql/psql.c
src/bin/psql/psql.c
+973
-771
No files found.
src/bin/psql/psql.c
View file @
7870c5a0
/
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*
*
*
psql
.
c
--
*
psql
.
c
--
*
an
interactive
front
-
end
to
postgres95
*
an
interactive
front
-
end
to
postgres95
...
@@ -7,7 +7,7 @@
...
@@ -7,7 +7,7 @@
*
*
*
*
*
IDENTIFICATION
*
IDENTIFICATION
* $Header: /cvsroot/pgsql/src/bin/psql/Attic/psql.c,v 1.2
3 1996/10/14 00:33:47 momjian
Exp $
*
$
Header
:
/
cvsroot
/
pgsql
/
src
/
bin
/
psql
/
Attic
/
psql
.
c
,
v
1
.
2
4
1996
/
11
/
04
09
:
17
:
55
bryanh
Exp
$
*
*
*-------------------------------------------------------------------------
*-------------------------------------------------------------------------
*/
*/
...
@@ -24,7 +24,7 @@
...
@@ -24,7 +24,7 @@
#include "psqlHelp.h"
#include "psqlHelp.h"
#ifdef NOREADLINE
#ifdef NOREADLINE
extern
char
*
readline
(
char
*
);
/* in rlstubs.c */
extern
char
*
readline
(
char
*
);
/* in rlstubs.c */
#else
#else
/* from the GNU readline library */
/* from the GNU readline library */
#ifdef OLD_READLINE
#ifdef OLD_READLINE
...
@@ -38,20 +38,20 @@ extern char *readline(char *); /* in rlstubs.c */
...
@@ -38,20 +38,20 @@ extern char *readline(char *); /* in rlstubs.c */
#define MAX_QUERY_BUFFER 20000
#define MAX_QUERY_BUFFER 20000
#define COPYBUFSIZ
8192
#define COPYBUFSIZ
8192
#define DEFAULT_FIELD_SEP "|"
#define DEFAULT_FIELD_SEP "|"
#define DEFAULT_EDITOR "vi"
#define DEFAULT_EDITOR "vi"
#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 */
...
@@ -62,8 +62,9 @@ typedef struct _psqlSettings {
...
@@ -62,8 +62,9 @@ typedef struct _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
);
static
void
handleCopyOut
(
PGresult
*
res
,
bool
quiet
,
FILE
*
copystream
);
static
void
handleCopyIn
(
PGresult
*
res
,
bool
quiet
);
static
void
handleCopyIn
(
PGresult
*
res
,
const
bool
mustprompt
,
FILE
*
copystream
);
static
int
tableList
(
PsqlSettings
*
ps
,
bool
deep_tablelist
);
static
int
tableList
(
PsqlSettings
*
ps
,
bool
deep_tablelist
);
static
int
tableDesc
(
PsqlSettings
*
ps
,
char
*
table
);
static
int
tableDesc
(
PsqlSettings
*
ps
,
char
*
table
);
...
@@ -71,16 +72,17 @@ char *gets_noreadline(char *prompt, FILE *source);
...
@@ -71,16 +72,17 @@ char *gets_noreadline(char *prompt, FILE *source);
char
*
gets_readline
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_readline
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_fromFile
(
char
*
prompt
,
FILE
*
source
);
char
*
gets_fromFile
(
char
*
prompt
,
FILE
*
source
);
int
listAllDbs
(
PsqlSettings
*
settings
);
int
listAllDbs
(
PsqlSettings
*
settings
);
int
SendQuery
(
PsqlSettings
*
settings
,
char
*
query
);
void
SendQuery
(
bool
*
success_p
,
PsqlSettings
*
settings
,
const
char
*
query
,
const
bool
copy_in
,
const
bool
copy_out
,
FILE
*
copystream
);
int
HandleSlashCmds
(
PsqlSettings
*
settings
,
int
HandleSlashCmds
(
PsqlSettings
*
settings
,
char
*
line
,
char
*
line
,
char
*
query
);
char
*
query
);
int
MainLoop
(
PsqlSettings
*
settings
,
FILE
*
source
);
int
MainLoop
(
PsqlSettings
*
settings
,
FILE
*
source
);
/* probably should move this into libpq */
/* probably should move this into libpq */
void
PQprint
(
FILE
*
fp
,
void
PQprint
(
FILE
*
fp
,
PGresult
*
res
,
PGresult
*
res
,
PQprintOpt
*
po
PQprintOpt
*
po
);
);
FILE
*
setFout
(
PsqlSettings
*
ps
,
char
*
fname
);
FILE
*
setFout
(
PsqlSettings
*
ps
,
char
*
fname
);
...
@@ -122,7 +124,7 @@ usage(char *progname)
...
@@ -122,7 +124,7 @@ usage(char *progname)
char
*
on
(
bool
f
)
char
*
on
(
bool
f
)
{
{
return
f
?
"on"
:
"off"
;
return
f
?
"on"
:
"off"
;
}
}
static
void
static
void
...
@@ -131,7 +133,8 @@ slashUsage(PsqlSettings *ps)
...
@@ -131,7 +133,8 @@ slashUsage(PsqlSettings *ps)
fprintf
(
stderr
,
"
\t
\\
? -- help
\n
"
);
fprintf
(
stderr
,
"
\t
\\
? -- help
\n
"
);
fprintf
(
stderr
,
"
\t
\\
a -- toggle field-alignment (currenty %s)
\n
"
,
on
(
ps
->
opt
.
align
));
fprintf
(
stderr
,
"
\t
\\
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
,
"
\t
\\
C [<captn>] -- set html3 caption (currently '%s')
\n
"
,
ps
->
opt
.
caption
?
ps
->
opt
.
caption
:
""
);
fprintf
(
stderr
,
"
\t
\\
c <dbname> -- connect to new database (currently '%s')
\n
"
,
PQdb
(
ps
->
db
));
fprintf
(
stderr
,
"
\t
\\
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
,
"
\t
\\
d [<table>] -- list tables in database or columns in <table>,* for all
\n
"
);
fprintf
(
stderr
,
"
\t
\\
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
,
"
\t
\\
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
,
"
\t
\\
f [<sep>] -- change field separater (currently '%s')
\n
"
,
ps
->
opt
.
fieldSep
);
...
@@ -157,19 +160,19 @@ slashUsage(PsqlSettings *ps)
...
@@ -157,19 +160,19 @@ slashUsage(PsqlSettings *ps)
PGresult
*
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
...
@@ -192,7 +195,7 @@ listAllDbs(PsqlSettings *ps)
...
@@ -192,7 +195,7 @@ listAllDbs(PsqlSettings *ps)
{
{
PQprint
(
ps
->
queryFout
,
PQprint
(
ps
->
queryFout
,
results
,
results
,
&
ps
->
opt
);
&
ps
->
opt
);
PQclear
(
results
);
PQclear
(
results
);
return
0
;
return
0
;
}
}
...
@@ -226,55 +229,55 @@ tableList (PsqlSettings *ps, bool deep_tablelist)
...
@@ -226,55 +229,55 @@ tableList (PsqlSettings *ps, bool deep_tablelist)
strcat
(
listbuf
,
" and usesysid = relowner"
);
strcat
(
listbuf
,
" and usesysid = relowner"
);
strcat
(
listbuf
,
" ORDER BY relname "
);
strcat
(
listbuf
,
" ORDER BY relname "
);
if
(
!
(
res
=
PSQLexec
(
ps
,
listbuf
)))
if
(
!
(
res
=
PSQLexec
(
ps
,
listbuf
)))
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
)
{
{
if
(
deep_tablelist
)
{
if
(
deep_tablelist
)
{
/* describe everything here */
/* describe everything here */
char
**
table
;
char
**
table
;
table
=
(
char
**
)
malloc
(
nColumns
*
sizeof
(
char
*
));
table
=
(
char
**
)
malloc
(
nColumns
*
sizeof
(
char
*
));
if
(
table
==
NULL
)
if
(
table
==
NULL
)
perror
(
"malloc"
);
perror
(
"malloc"
);
/* load table table */
/* load table table */
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
table
[
i
]
=
(
char
*
)
malloc
(
PQgetlength
(
res
,
i
,
1
)
*
sizeof
(
char
)
+
1
);
table
[
i
]
=
(
char
*
)
malloc
(
PQgetlength
(
res
,
i
,
1
)
*
sizeof
(
char
)
+
1
);
if
(
table
[
i
]
==
NULL
)
if
(
table
[
i
]
==
NULL
)
perror
(
"malloc"
);
perror
(
"malloc"
);
strcpy
(
table
[
i
],
PQgetvalue
(
res
,
i
,
1
));
strcpy
(
table
[
i
],
PQgetvalue
(
res
,
i
,
1
));
}
}
PQclear
(
res
);
PQclear
(
res
);
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
for
(
i
=
0
;
i
<
nColumns
;
i
++
)
{
tableDesc
(
ps
,
table
[
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
"
);
printf
(
" +------------------+----------------------------------+----------+
\n
"
);
PQclear
(
res
);
PQclear
(
res
);
}
}
return
(
0
);
return
(
0
);
...
@@ -316,7 +319,7 @@ tableDesc (PsqlSettings *ps, char *table)
...
@@ -316,7 +319,7 @@ tableDesc (PsqlSettings *ps, char *table)
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
)
...
@@ -348,21 +351,21 @@ tableDesc (PsqlSettings *ps, char *table)
...
@@ -348,21 +351,21 @@ tableDesc (PsqlSettings *ps, char *table)
printf
(
"%6i |"
,
rsize
>
0
?
rsize
-
4
:
0
);
printf
(
"%6i |"
,
rsize
>
0
?
rsize
-
4
:
0
);
}
}
else
{
else
{
/* array types start with an underscore */
/* array types start with an underscore */
if
(
rtype
[
0
]
!=
'_'
)
if
(
rtype
[
0
]
!=
'_'
)
printf
(
"%-32.32s |"
,
rtype
);
printf
(
"%-32.32s |"
,
rtype
);
else
{
else
{
char
*
newname
;
char
*
newname
;
newname
=
malloc
(
strlen
(
rtype
)
+
2
);
newname
=
malloc
(
strlen
(
rtype
)
+
2
);
strcpy
(
newname
,
rtype
+
1
);
strcpy
(
newname
,
rtype
+
1
);
strcat
(
newname
,
"[]"
);
strcat
(
newname
,
"[]"
);
printf
(
"%-32.32s |"
,
newname
);
printf
(
"%-32.32s |"
,
newname
);
free
(
newname
);
free
(
newname
);
}
}
if
(
rsize
>
0
)
if
(
rsize
>
0
)
printf
(
"%6i |"
,
rsize
);
printf
(
"%6i |"
,
rsize
);
else
else
printf
(
"%6s |"
,
"var"
);
printf
(
"%6s |"
,
"var"
);
}
}
printf
(
"
\n
"
);
printf
(
"
\n
"
);
}
}
...
@@ -423,7 +426,8 @@ gets_fromFile(char *prompt, FILE *source)
...
@@ -423,7 +426,8 @@ gets_fromFile(char *prompt, FILE *source)
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
"
,
MAX_QUERY_BUFFER
);
fprintf
(
stderr
,
"line read exceeds maximum length. Truncating at %d
\n
"
,
MAX_QUERY_BUFFER
);
}
}
return
line
;
return
line
;
...
@@ -431,18 +435,19 @@ gets_fromFile(char *prompt, FILE *source)
...
@@ -431,18 +435,19 @@ gets_fromFile(char *prompt, FILE *source)
/*
/*
* SendQuery: send the query string to the backend
* SendQuery: send the query string to the backend
* return
0
if the query executed successfully
* return
*success_p = 1
if the query executed successfully
* returns
1
otherwise
* returns
*success_p = 0
otherwise
*/
*/
int
void
SendQuery
(
PsqlSettings
*
settings
,
char
*
query
)
SendQuery
(
bool
*
success_p
,
PsqlSettings
*
settings
,
const
char
*
query
,
{
const
bool
copy_in
,
const
bool
copy_out
,
FILE
*
copystream
)
{
PGresult
*
results
;
PGresult
*
results
;
PGnotify
*
notify
;
PGnotify
*
notify
;
int
status
=
0
;
if
(
settings
->
singleStep
)
if
(
settings
->
singleStep
)
fprintf
(
stdout
,
"
\n
*******************************************************************************
\n
"
);
fprintf
(
stdout
,
"
\n
**************************************"
"*****************************************
\n
"
);
if
(
settings
->
echoQuery
||
settings
->
singleStep
)
{
if
(
settings
->
echoQuery
||
settings
->
singleStep
)
{
fprintf
(
stderr
,
"QUERY: %s
\n
"
,
query
);
fprintf
(
stderr
,
"QUERY: %s
\n
"
,
query
);
...
@@ -450,81 +455,102 @@ SendQuery(PsqlSettings *settings, char *query)
...
@@ -450,81 +455,102 @@ SendQuery(PsqlSettings *settings, char *query)
}
}
if
(
settings
->
singleStep
)
{
if
(
settings
->
singleStep
)
{
fprintf
(
stdout
,
"
\n
*******************************************************************************
\n
"
);
fprintf
(
stdout
,
"
\n
**************************************"
fflush
(
stdout
);
"*****************************************
\n
"
);
printf
(
"
\n
press return to continue ..
\n
"
);
fflush
(
stdout
);
gets_fromFile
(
""
,
stdin
);
printf
(
"
\n
press return to continue ..
\n
"
);
gets_fromFile
(
""
,
stdin
);
}
}
results
=
PQexec
(
settings
->
db
,
query
);
results
=
PQexec
(
settings
->
db
,
query
);
if
(
results
==
NULL
)
{
if
(
results
==
NULL
)
{
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
return
1
;
*
success_p
=
false
;
}
}
else
{
switch
(
PQresultStatus
(
results
))
{
switch
(
PQresultStatus
(
results
))
{
case
PGRES_TUPLES_OK
:
case
PGRES_TUPLES_OK
:
if
(
settings
->
gfname
)
{
if
(
settings
->
gfname
)
PsqlSettings
ps
=*
settings
;
{
FILE
*
fp
;
PsqlSettings
ps
=*
settings
;
ps
.
queryFout
=
stdout
;
FILE
*
fp
;
fp
=
setFout
(
&
ps
,
settings
->
gfname
);
ps
.
queryFout
=
stdout
;
if
(
!
fp
||
fp
==
stdout
)
{
fp
=
setFout
(
&
ps
,
settings
->
gfname
);
*
success_p
=
false
;
if
(
!
fp
||
fp
==
stdout
)
break
;
{
}
else
*
success_p
=
true
;
status
=
1
;
PQprint
(
fp
,
break
;
results
,
}
&
(
settings
->
opt
));
PQprint
(
fp
,
if
(
ps
.
pipe
)
results
,
pclose
(
fp
);
&
(
settings
->
opt
));
else
if
(
ps
.
pipe
)
fclose
(
fp
);
pclose
(
fp
);
settings
->
gfname
=
NULL
;
else
break
;
fclose
(
fp
);
}
else
{
settings
->
gfname
=
NULL
;
*
success_p
=
true
;
break
;
PQprint
(
settings
->
queryFout
,
}
else
results
,
{
&
(
settings
->
opt
));
PQprint
(
settings
->
queryFout
,
fflush
(
settings
->
queryFout
);
results
,
}
&
(
settings
->
opt
));
PQclear
(
results
);
fflush
(
settings
->
queryFout
);
break
;
}
case
PGRES_EMPTY_QUERY
:
PQclear
(
results
);
*
success_p
=
true
;
break
;
break
;
case
PGRES_EMPTY_QUERY
:
case
PGRES_COMMAND_OK
:
/* do nothing */
*
success_p
=
true
;
break
;
if
(
!
settings
->
quiet
)
case
PGRES_COMMAND_OK
:
fprintf
(
stdout
,
"%s
\n
"
,
PQcmdStatus
(
results
));
if
(
!
settings
->
quiet
)
break
;
fprintf
(
stdout
,
"%s
\n
"
,
PQcmdStatus
(
results
));
case
PGRES_COPY_OUT
:
break
;
*
success_p
=
true
;
case
PGRES_COPY_OUT
:
if
(
copy_out
)
{
handleCopyOut
(
results
,
settings
->
quiet
);
handleCopyOut
(
results
,
settings
->
quiet
,
copystream
);
break
;
}
else
{
case
PGRES_COPY_IN
:
if
(
!
settings
->
quiet
)
handleCopyIn
(
results
,
settings
->
quiet
);
fprintf
(
stdout
,
"Copy command returns...
\n
"
);
break
;
case
PGRES_NONFATAL_ERROR
:
handleCopyOut
(
results
,
settings
->
quiet
,
stdout
);
case
PGRES_FATAL_ERROR
:
}
case
PGRES_BAD_RESPONSE
:
break
;
status
=
1
;
case
PGRES_COPY_IN
:
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
*
success_p
=
true
;
break
;
if
(
copy_in
)
{
}
handleCopyIn
(
results
,
false
,
copystream
);
}
else
{
/* check for asynchronous returns */
char
c
;
notify
=
PQnotifies
(
settings
->
db
);
/*
if
(
notify
)
{
* eat extra newline still in input buffer
fprintf
(
stderr
,
"ASYNC NOTIFY of '%s' from backend pid '%d' received
\n
"
,
*
notify
->
relname
,
notify
->
be_pid
);
*/
free
(
notify
);
fflush
(
stdin
);
if
((
c
=
getc
(
stdin
))
!=
'\n'
&&
c
!=
EOF
)
(
void
)
ungetc
(
c
,
stdin
);
handleCopyIn
(
results
,
!
settings
->
quiet
,
stdin
);
}
break
;
case
PGRES_NONFATAL_ERROR
:
case
PGRES_FATAL_ERROR
:
case
PGRES_BAD_RESPONSE
:
*
success_p
=
false
;
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
->
db
));
break
;
}
/* 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
);
}
}
}
}
return
status
;
}
void
void
editFile
(
char
*
fname
)
editFile
(
char
*
fname
)
...
@@ -533,12 +559,12 @@ editFile(char *fname)
...
@@ -533,12 +559,12 @@ editFile(char *fname)
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
);
...
@@ -548,49 +574,360 @@ editFile(char *fname)
...
@@ -548,49 +574,360 @@ editFile(char *fname)
bool
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
;
}
}
void
void
decode
(
char
*
s
)
unescape
(
char
*
dest
,
const
char
*
source
)
{
{
/*-----------------------------------------------------------------------------
char
*
p
,
*
d
;
Return as the string <dest> the value of string <source> with escape
bool
esc
=
0
;
sequences turned into the bytes they represent.
for
(
d
=
p
=
s
;
*
p
;
p
++
)
-----------------------------------------------------------------------------*/
{
char
*
p
;
char
c
=*
p
;
bool
esc
;
/* Last character we saw was the escape character (/) */
if
(
esc
)
{
esc
=
false
;
/* Haven't seen escape character yet */
switch
(
*
p
)
for
(
p
=
(
char
*
)
source
;
*
p
;
p
++
)
{
{
char
c
;
/* Our output character */
case
'n'
:
c
=
'\n'
;
if
(
esc
)
{
break
;
switch
(
*
p
)
{
case
'r'
:
case
'n'
:
c
=
'\r'
;
c
=
'\n'
;
break
;
break
;
case
't'
:
case
'r'
:
c
=
'\t'
;
c
=
'\r'
;
break
;
break
;
case
'f'
:
case
't'
:
c
=
'\f'
;
c
=
'\t'
;
break
;
break
;
}
case
'f'
:
esc
=
0
;
c
=
'\f'
;
}
else
break
;
if
(
c
==
'\\'
)
case
'\\'
:
{
c
=
'\\'
;
esc
=
1
;
break
;
continue
;
default:
}
c
=
*
p
;
*
d
++=
c
;
}
}
esc
=
false
;
*
d
=
'\0'
;
}
else
if
(
*
p
==
'\\'
)
{
esc
=
true
;
c
=
' '
;
/* meaningless, but compiler doesn't know that */
}
else
{
c
=
*
p
;
esc
=
false
;
}
if
(
!
esc
)
*
dest
++=
c
;
}
*
dest
=
'\0'
;
/* Terminating null character */
}
}
void
parse_slash_copy
(
const
char
*
args
,
char
*
table
,
const
int
table_len
,
char
*
file
,
const
int
file_len
,
bool
*
from_p
,
bool
*
error_p
)
{
char
work_args
[
200
];
/* A copy of the \copy command arguments, except that we modify it
as we parse to suit our parsing needs.
*/
char
*
table_tok
,
*
fromto_tok
;
strncpy
(
work_args
,
args
,
sizeof
(
work_args
));
work_args
[
sizeof
(
work_args
)
-
1
]
=
'\0'
;
*
error_p
=
false
;
/* initial assumption */
table_tok
=
strtok
(
work_args
,
" "
);
if
(
table_tok
==
NULL
)
{
fprintf
(
stderr
,
"
\\
copy needs arguments.
\n
"
);
*
error_p
=
true
;
}
else
{
strncpy
(
table
,
table_tok
,
table_len
);
file
[
table_len
-
1
]
=
'\0'
;
fromto_tok
=
strtok
(
NULL
,
" "
);
if
(
fromto_tok
==
NULL
)
{
fprintf
(
stderr
,
"'FROM' or 'TO' must follow table name.
\n
"
);
*
error_p
=
true
;
}
else
{
if
(
strcasecmp
(
fromto_tok
,
"from"
)
==
0
)
*
from_p
=
true
;
else
if
(
strcasecmp
(
fromto_tok
,
"to"
)
==
0
)
*
from_p
=
false
;
else
{
fprintf
(
stderr
,
"Unrecognized token found where "
"'FROM' or 'TO' expected: '%s'.
\n
"
,
fromto_tok
);
*
error_p
=
true
;
}
if
(
!*
error_p
)
{
char
*
file_tok
;
file_tok
=
strtok
(
NULL
,
" "
);
if
(
file_tok
==
NULL
)
{
fprintf
(
stderr
,
"A file pathname must follow '%s'.
\n
"
,
fromto_tok
);
*
error_p
=
true
;
}
else
{
strncpy
(
file
,
file_tok
,
file_len
);
file
[
file_len
-
1
]
=
'\0'
;
if
(
strtok
(
NULL
,
" "
)
!=
NULL
)
{
fprintf
(
stderr
,
"You have extra tokens after the filename.
\n
"
);
*
error_p
=
true
;
}
}
}
}
}
}
void
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
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.
----------------------------------------------------------------------------*/
char
query
[
200
];
/* The COPY command we send to the back end */
bool
from
;
/* The direction of the copy is from a file to a table. */
char
file
[
MAXPATHLEN
+
1
];
/* The pathname of the file from/to which we copy */
char
table
[
NAMEDATALEN
+
1
];
/* The name of the table from/to which we copy */
bool
syntax_error
;
/* The \c command has invalid syntax */
FILE
*
copystream
;
parse_slash_copy
(
args
,
table
,
sizeof
(
table
),
file
,
sizeof
(
file
),
&
from
,
&
syntax_error
);
if
(
!
syntax_error
)
{
strcpy
(
query
,
"COPY "
);
strcat
(
query
,
table
);
if
(
from
)
strcat
(
query
,
" FROM stdin"
);
else
strcat
(
query
,
" TO stdout"
);
if
(
from
)
{
copystream
=
fopen
(
file
,
"r"
);
}
else
{
copystream
=
fopen
(
file
,
"w"
);
}
if
(
copystream
<
0
)
fprintf
(
stderr
,
"Unable to open file %s which to copy, errno = %s (%d)."
,
from
?
"from"
:
"to"
,
strerror
(
errno
),
errno
);
else
{
bool
success
;
/* The query succeeded at the backend */
SendQuery
(
&
success
,
settings
,
query
,
from
,
!
from
,
copystream
);
fclose
(
copystream
);
if
(
!
settings
->
quiet
)
{
if
(
success
)
fprintf
(
stdout
,
"Successfully copied.
\n
"
);
else
fprintf
(
stdout
,
"Copy failed.
\n
"
);
}
}
}
}
void
do_connect
(
const
char
*
new_dbname
,
PsqlSettings
*
settings
)
{
char
*
dbname
=
PQdb
(
settings
->
db
);
if
(
!
new_dbname
)
fprintf
(
stderr
,
"
\\
connect must be followed by a database name
\n
"
);
else
{
PGconn
*
olddb
=
settings
->
db
;
printf
(
"closing connection to database: %s
\n
"
,
dbname
);
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
NULL
,
NULL
,
new_dbname
);
printf
(
"connecting to new database: %s
\n
"
,
new_dbname
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
"%s
\n
"
,
PQerrorMessage
(
settings
->
db
));
printf
(
"reconnecting to %s
\n
"
,
dbname
);
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
NULL
,
NULL
,
dbname
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
"could not reconnect to %s. exiting
\n
"
,
dbname
);
exit
(
2
);
}
}
else
{
PQfinish
(
olddb
);
free
(
settings
->
prompt
);
settings
->
prompt
=
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
10
);
sprintf
(
settings
->
prompt
,
"%s=> "
,
PQdb
(
settings
->
db
));
}
}
}
void
do_edit
(
const
char
*
filename_arg
,
char
*
query
,
int
*
retcode_p
)
{
int
fd
;
char
tmp
[
64
];
char
*
fname
;
int
cc
;
const
int
ql
=
strlen
(
query
);
bool
error
;
if
(
filename_arg
)
{
fname
=
(
char
*
)
filename_arg
;
error
=
false
;
}
else
{
sprintf
(
tmp
,
"/tmp/psql.%d.%d"
,
geteuid
(),
getpid
());
fname
=
tmp
;
unlink
(
tmp
);
if
(
ql
>
0
)
{
if
((
fd
=
open
(
tmp
,
O_EXCL
|
O_CREAT
|
O_WRONLY
,
0600
))
==
-
1
)
{
perror
(
tmp
);
error
=
true
;
}
else
{
if
(
query
[
ql
-
1
]
!=
'\n'
)
strcat
(
query
,
"
\n
"
);
if
(
write
(
fd
,
query
,
ql
)
!=
ql
)
{
perror
(
tmp
);
close
(
fd
);
unlink
(
tmp
);
error
=
true
;
}
else
error
=
false
;
close
(
fd
);
}
}
else
error
=
false
;
}
if
(
error
)
*
retcode_p
=
1
;
else
{
editFile
(
fname
);
if
((
fd
=
open
(
fname
,
O_RDONLY
))
==-
1
)
{
perror
(
fname
);
if
(
!
filename_arg
)
unlink
(
fname
);
*
retcode_p
=
1
;
}
else
{
if
((
cc
=
read
(
fd
,
query
,
MAX_QUERY_BUFFER
))
==-
1
)
{
perror
(
fname
);
close
(
fd
);
if
(
!
filename_arg
)
unlink
(
fname
);
*
retcode_p
=
1
;
}
else
{
query
[
cc
]
=
'\0'
;
close
(
fd
);
if
(
!
filename_arg
)
unlink
(
fname
);
rightTrim
(
query
);
if
(
query
[
strlen
(
query
)
-
1
]
==
';'
)
*
retcode_p
=
0
;
else
*
retcode_p
=
1
;
}
}
}
}
void
do_help
(
const
char
*
topic
)
{
if
(
!
topic
)
{
char
left_center_right
;
/* Which column we're displaying */
int
i
;
/* Index into QL_HELP[] */
printf
(
"type
\\
h <cmd> where <cmd> is one of the following:
\n
"
);
left_center_right
=
'L'
;
/* Start with left column */
i
=
0
;
while
(
QL_HELP
[
i
].
cmd
!=
NULL
)
{
switch
(
left_center_right
)
{
case
'L'
:
printf
(
" %-25s"
,
QL_HELP
[
i
].
cmd
);
left_center_right
=
'C'
;
break
;
case
'C'
:
printf
(
"%-25s"
,
QL_HELP
[
i
].
cmd
);
left_center_right
=
'R'
;
break
;
case
'R'
:
printf
(
"%-25s
\n
"
,
QL_HELP
[
i
].
cmd
);
left_center_right
=
'L'
;
break
;
};
i
++
;
}
if
(
left_center_right
!=
'L'
)
puts
(
"
\n
"
);
printf
(
"type
\\
h * for a complete description of all commands
\n
"
);
}
else
{
int
i
;
/* Index into QL_HELP[] */
bool
help_found
;
/* We found the help he asked for */
help_found
=
false
;
/* Haven't found it yet */
for
(
i
=
0
;
QL_HELP
[
i
].
cmd
;
i
++
)
{
if
(
strcmp
(
QL_HELP
[
i
].
cmd
,
topic
)
==
0
||
strcmp
(
topic
,
"*"
)
==
0
)
{
help_found
=
true
;
printf
(
"Command: %s
\n
"
,
QL_HELP
[
i
].
cmd
);
printf
(
"Description: %s
\n
"
,
QL_HELP
[
i
].
help
);
printf
(
"Syntax:
\n
"
);
printf
(
"%s
\n
"
,
QL_HELP
[
i
].
syntax
);
printf
(
"
\n
"
);
}
}
if
(
!
help_found
)
printf
(
"command not found, "
"try
\\
h with no arguments to see available help
\n
"
);
}
}
void
do_shell
(
const
char
*
command
)
{
if
(
!
command
)
{
char
*
sys
;
char
*
shellName
;
shellName
=
getenv
(
"SHELL"
);
if
(
shellName
==
NULL
)
shellName
=
DEFAULT_SHELL
;
sys
=
malloc
(
strlen
(
shellName
)
+
16
);
if
(
!
sys
)
{
perror
(
"malloc"
);
exit
(
1
);
}
sprintf
(
sys
,
"exec %s"
,
shellName
);
system
(
sys
);
free
(
sys
);
}
else
system
(
command
);
}
/*
/*
HandleSlashCmds:
HandleSlashCmds:
...
@@ -599,7 +936,7 @@ decode(char *s)
...
@@ -599,7 +936,7 @@ decode(char *s)
line is the current input line
line is the current input line
prompt_ptr is a pointer to the prompt string,
prompt_ptr is a pointer to the prompt string,
a pointer is used because the prompt can be used with
a pointer is used because the prompt can be used with
a connection to a new database
a connection to a new database
returns a status:
returns a status:
0 - send currently constructed query to backend (i.e. we got a \g)
0 - send currently constructed query to backend (i.e. we got a \g)
1 - skip processing of this line, continue building up query
1 - skip processing of this line, continue building up query
...
@@ -607,287 +944,179 @@ decode(char *s)
...
@@ -607,287 +944,179 @@ decode(char *s)
*/
*/
int
int
HandleSlashCmds
(
PsqlSettings
*
settings
,
HandleSlashCmds
(
PsqlSettings
*
settings
,
char
*
line
,
char
*
line
,
char
*
query
)
char
*
query
)
{
{
int
status
=
1
;
int
status
=
1
;
char
*
optarg
=
NULL
;
char
*
optarg
;
int
len
;
/* Pointer inside the <cmd> string to the argument of the slash
command, 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
command assuming it's not a one-character command. If it's a
one-character command, this is meaningless.
*/
char
*
cmd
;
/* String: value of the slash command, less the slash and with escape
sequences decoded.
*/
int
blank_loc
;
/* Offset within <cmd> of first blank */
cmd
=
malloc
(
strlen
(
line
));
/* unescaping better not make string grow. */
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
the old single character commands too. \c used to be what
\connect is now. Complicating matters is the fact that with
the single-character commands, you can start the argument
right after the single character, so "\copy" would mean
"connect to database named 'opy'".
*/
len
=
strlen
(
line
);
if
(
strlen
(
cmd
)
>
1
)
optarg
=
cmd
+
1
+
strspn
(
cmd
+
1
,
"
\t
"
);
if
(
len
>
2
)
else
optarg
=
NULL
;
{
optarg
=
leftTrim
(
line
+
2
);
blank_loc
=
strcspn
(
cmd
,
"
\t
"
);
decode
(
optarg
);
if
(
blank_loc
==
0
)
optarg2
=
NULL
;
}
else
optarg2
=
cmd
+
blank_loc
+
strspn
(
cmd
+
blank_loc
,
"
\t
"
);
switch
(
line
[
1
])
switch
(
cmd
[
0
])
{
{
case
'a'
:
/* toggles to align fields on output */
case
'a'
:
/* toggles to align fields on output */
toggle
(
settings
,
&
settings
->
opt
.
align
,
"field alignment"
);
toggle
(
settings
,
&
settings
->
opt
.
align
,
"field alignment"
);
break
;
break
;
case
'C'
:
/* define new caption */
case
'C'
:
/* define new caption */
if
(
settings
->
opt
.
caption
)
if
(
settings
->
opt
.
caption
)
free
(
settings
->
opt
.
caption
);
free
(
settings
->
opt
.
caption
);
if
(
!
optarg
)
if
(
!
optarg
)
settings
->
opt
.
caption
=
NULL
;
settings
->
opt
.
caption
=
NULL
;
else
else
if
(
!
(
settings
->
opt
.
caption
=
strdup
(
optarg
)))
if
(
!
(
settings
->
opt
.
caption
=
strdup
(
optarg
)))
{
{
perror
(
"malloc"
);
perror
(
"malloc"
);
exit
(
1
);
exit
(
1
);
}
}
break
;
break
;
case
'c'
:
/* \c means connect to new database */
case
'c'
:
{
{
if
(
strncmp
(
cmd
,
"copy "
,
strlen
(
"copy "
))
==
0
)
char
*
dbname
=
PQdb
(
settings
->
db
);
do_copy
(
optarg2
,
settings
);
if
(
!
optarg
)
{
else
if
(
strncmp
(
cmd
,
"connect "
,
strlen
(
"connect "
))
==
0
)
fprintf
(
stderr
,
"
\\
c must be followed by a database name
\n
"
);
do_connect
(
optarg2
,
settings
);
break
;
else
}
do_connect
(
optarg
,
settings
);
{
PGconn
*
olddb
=
settings
->
db
;
printf
(
"closing connection to database: %s
\n
"
,
dbname
);
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
NULL
,
NULL
,
optarg
);
printf
(
"connecting to new database: %s
\n
"
,
optarg
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
"%s
\n
"
,
PQerrorMessage
(
settings
->
db
));
printf
(
"reconnecting to %s
\n
"
,
dbname
);
settings
->
db
=
PQsetdb
(
PQhost
(
olddb
),
PQport
(
olddb
),
NULL
,
NULL
,
dbname
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
"could not reconnect to %s. exiting
\n
"
,
dbname
);
exit
(
2
);
}
break
;
}
PQfinish
(
olddb
);
free
(
settings
->
prompt
);
settings
->
prompt
=
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
10
);
sprintf
(
settings
->
prompt
,
"%s=> "
,
PQdb
(
settings
->
db
));
break
;
}
}
}
break
;
break
;
case
'd'
:
/* \d describe tables or columns in a table */
case
'd'
:
/* \d describe tables or columns in a table */
if
(
!
optarg
)
{
if
(
!
optarg
)
{
tableList
(
settings
,
0
);
tableList
(
settings
,
0
);
break
;
break
;
}
}
if
(
strcmp
(
optarg
,
"*"
)
==
0
)
{
if
(
strcmp
(
optarg
,
"*"
)
==
0
)
{
tableList
(
settings
,
0
);
tableList
(
settings
,
0
);
tableList
(
settings
,
1
);
tableList
(
settings
,
1
);
}
}
else
{
else
{
tableDesc
(
settings
,
optarg
);
tableDesc
(
settings
,
optarg
);
}
}
break
;
break
;
case
'e'
:
case
'e'
:
/* edit */
{
{
int
fd
;
do_edit
(
optarg
,
query
,
&
status
);
char
tmp
[
64
];
break
;
char
*
fname
;
int
cc
;
int
ql
=
strlen
(
query
);
if
(
optarg
)
fname
=
optarg
;
else
{
sprintf
(
tmp
,
"/tmp/psql.%d.%d"
,
geteuid
(),
getpid
());
fname
=
tmp
;
unlink
(
tmp
);
if
(
ql
)
{
if
((
fd
=
open
(
tmp
,
O_EXCL
|
O_CREAT
|
O_WRONLY
,
0600
))
==-
1
)
{
perror
(
tmp
);
break
;
}
if
(
query
[
ql
-
1
]
!=
'\n'
)
strcat
(
query
,
"
\n
"
);
if
(
write
(
fd
,
query
,
ql
)
!=
ql
)
{
perror
(
tmp
);
close
(
fd
);
unlink
(
tmp
);
break
;
}
close
(
fd
);
}
}
editFile
(
fname
);
if
((
fd
=
open
(
fname
,
O_RDONLY
))
==-
1
)
{
perror
(
fname
);
if
(
!
optarg
)
unlink
(
fname
);
break
;
}
if
((
cc
=
read
(
fd
,
query
,
MAX_QUERY_BUFFER
))
==-
1
)
{
perror
(
fname
);
close
(
fd
);
if
(
!
optarg
)
unlink
(
fname
);
break
;
}
query
[
cc
]
=
'\0'
;
close
(
fd
);
if
(
!
optarg
)
unlink
(
fname
);
rightTrim
(
query
);
if
(
query
[
strlen
(
query
)
-
1
]
==
';'
)
return
0
;
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"
);
perror
(
"malloc"
);
exit
(
1
);
exit
(
1
);
}
}
strcpy
(
lastfile
,
optarg
);
strcpy
(
lastfile
,
optarg
);
}
else
if
(
!
lastfile
)
}
else
if
(
!
lastfile
)
{
{
fprintf
(
stderr
,
"
\\
r must be followed by a file name initially
\n
"
);
fprintf
(
stderr
,
"
\\
r must be followed by a file name initially
\n
"
);
break
;
break
;
}
}
stat
(
lastfile
,
&
st
);
stat
(
lastfile
,
&
st
);
editFile
(
lastfile
);
editFile
(
lastfile
);
if
((
stat
(
lastfile
,
&
st2
)
==
-
1
)
||
((
fd
=
fopen
(
lastfile
,
"r"
))
==
NULL
))
if
((
stat
(
lastfile
,
&
st2
)
==
-
1
)
||
((
fd
=
fopen
(
lastfile
,
"r"
))
==
NULL
))
{
{
perror
(
lastfile
);
perror
(
lastfile
);
break
;
break
;
}
}
if
(
st2
.
st_mtime
==
st
.
st_mtime
)
if
(
st2
.
st_mtime
==
st
.
st_mtime
)
{
{
if
(
!
settings
->
quiet
)
if
(
!
settings
->
quiet
)
fprintf
(
stderr
,
"warning: %s not modified. query not executed
\n
"
,
lastfile
);
fprintf
(
stderr
,
"warning: %s not modified. query not executed
\n
"
,
lastfile
);
fclose
(
fd
);
fclose
(
fd
);
break
;
break
;
}
}
MainLoop
(
settings
,
fd
);
MainLoop
(
settings
,
fd
);
fclose
(
fd
);
fclose
(
fd
);
break
;
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'
:
case
'h'
:
/* help */
{
{
char
*
cmd
;
do_help
(
optarg
);
int
i
,
numCmds
;
break
;
int
all_help
=
0
;
char
left_center_right
=
'L'
;
if
(
!
optarg
)
{
printf
(
"type
\\
h <cmd> where <cmd> is one of the following:
\n
"
);
i
=
0
;
while
(
QL_HELP
[
i
].
cmd
!=
NULL
)
{
switch
(
left_center_right
)
{
case
'L'
:
printf
(
" %-25s"
,
QL_HELP
[
i
].
cmd
);
left_center_right
=
'C'
;
break
;
case
'C'
:
printf
(
"%-25s"
,
QL_HELP
[
i
].
cmd
);
left_center_right
=
'R'
;
break
;
case
'R'
:
printf
(
"%-25s
\n
"
,
QL_HELP
[
i
].
cmd
);
left_center_right
=
'L'
;
break
;
};
i
++
;
}
if
(
left_center_right
!=
'L'
)
puts
(
"
\n
"
);
printf
(
"type
\\
h * for a complete description of all commands
\n
"
);
}
else
{
cmd
=
optarg
;
numCmds
=
0
;
while
(
QL_HELP
[
numCmds
++
].
cmd
!=
NULL
);
numCmds
=
numCmds
-
1
;
if
(
strcmp
(
cmd
,
"*"
)
==
0
)
{
all_help
=
1
;
}
for
(
i
=
0
;
i
<
numCmds
;
i
++
)
{
if
(
strcmp
(
QL_HELP
[
i
].
cmd
,
cmd
)
==
0
||
all_help
)
{
printf
(
"Command: %s
\n
"
,
QL_HELP
[
i
].
cmd
);
printf
(
"Description: %s
\n
"
,
QL_HELP
[
i
].
help
);
printf
(
"Syntax:
\n
"
);
printf
(
"%s
\n
"
,
QL_HELP
[
i
].
syntax
);
if
(
all_help
)
{
printf
(
"
\n
"
);
}
else
{
break
;
}
}
}
if
(
i
==
numCmds
&&
!
all_help
)
printf
(
"command not found, try
\\
h with no arguments to see available help
\n
"
);
}
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
)
if
((
fd
=
fopen
(
optarg
,
"r"
))
==
NULL
)
{
{
fprintf
(
stderr
,
"file named %s could not be opened
\n
"
,
optarg
);
fprintf
(
stderr
,
"file named %s could not be opened
\n
"
,
optarg
);
break
;
break
;
}
}
MainLoop
(
settings
,
fd
);
MainLoop
(
settings
,
fd
);
fclose
(
fd
);
fclose
(
fd
);
break
;
break
;
}
}
case
'l'
:
/* \l is list database */
case
'l'
:
/* \l is list database */
listAllDbs
(
settings
);
listAllDbs
(
settings
);
break
;
break
;
case
'H'
:
case
'H'
:
if
(
toggle
(
settings
,
&
settings
->
opt
.
html3
,
"HTML3.0 tab
l
ular 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'
:
...
@@ -896,8 +1125,8 @@ HandleSlashCmds(PsqlSettings *settings,
...
@@ -896,8 +1125,8 @@ HandleSlashCmds(PsqlSettings *settings,
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 */
...
@@ -906,74 +1135,58 @@ HandleSlashCmds(PsqlSettings *settings,
...
@@ -906,74 +1135,58 @@ HandleSlashCmds(PsqlSettings *settings,
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
.
html3
=
settings
->
opt
.
expanded
=
0
;
settings
->
opt
.
align
=
settings
->
opt
.
header
=
1
;
settings
->
opt
.
align
=
settings
->
opt
.
header
=
1
;
free
(
settings
->
opt
.
fieldSep
);
free
(
settings
->
opt
.
fieldSep
);
settings
->
opt
.
fieldSep
=
strdup
(
"|"
);
settings
->
opt
.
fieldSep
=
strdup
(
"|"
);
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
);
}
else
}
else
{
{
free
(
settings
->
opt
.
fieldSep
);
free
(
settings
->
opt
.
fieldSep
);
settings
->
opt
.
fieldSep
=
strdup
(
DEFAULT_FIELD_SEP
);
settings
->
opt
.
fieldSep
=
strdup
(
DEFAULT_FIELD_SEP
);
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
't'
:
/* toggle headers */
case
't'
:
/* toggle headers */
toggle
(
settings
,
&
settings
->
opt
.
header
,
"output headings and row count"
);
toggle
(
settings
,
&
settings
->
opt
.
header
,
"output headings and row count"
);
break
;
break
;
case
'T'
:
/* define html <table ...> option */
case
'T'
:
/* define html <table ...> option */
if
(
settings
->
opt
.
tableOpt
)
if
(
settings
->
opt
.
tableOpt
)
free
(
settings
->
opt
.
tableOpt
);
free
(
settings
->
opt
.
tableOpt
);
if
(
!
optarg
)
if
(
!
optarg
)
settings
->
opt
.
tableOpt
=
NULL
;
settings
->
opt
.
tableOpt
=
NULL
;
else
else
if
(
!
(
settings
->
opt
.
tableOpt
=
strdup
(
optarg
)))
if
(
!
(
settings
->
opt
.
tableOpt
=
strdup
(
optarg
)))
{
{
perror
(
"malloc"
);
perror
(
"malloc"
);
exit
(
1
);
exit
(
1
);
}
}
break
;
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
'!'
:
if
(
!
optarg
)
{
do_shell
(
optarg
);
char
*
sys
;
char
*
shellName
;
shellName
=
getenv
(
"SHELL"
);
if
(
shellName
==
NULL
)
shellName
=
DEFAULT_SHELL
;
sys
=
malloc
(
strlen
(
shellName
)
+
16
);
if
(
!
sys
)
{
perror
(
"malloc"
);
exit
(
1
);
}
sprintf
(
sys
,
"exec %s"
,
shellName
);
system
(
sys
);
free
(
sys
);
}
else
system
(
optarg
);
break
;
break
;
default:
default:
case
'?'
:
/* \? is help */
case
'?'
:
/* \? is help */
slashUsage
(
settings
);
slashUsage
(
settings
);
break
;
break
;
}
}
free
(
cmd
);
return
status
;
return
status
;
}
}
...
@@ -990,152 +1203,151 @@ HandleSlashCmds(PsqlSettings *settings,
...
@@ -990,152 +1203,151 @@ HandleSlashCmds(PsqlSettings *settings,
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
exitStatus
=
0
;
int
slashCmdStatus
=
0
;
int
slashCmdStatus
=
0
;
/* slashCmdStatus can be:
/* slashCmdStatus can be:
0 - send currently constructed query to backend (i.e. we got a \g)
0 - send currently constructed query to backend (i.e. we got a \g)
1 - skip processing of this line, continue building up query
1 - skip processing of this line, continue building up query
2 - terminate processing of this query entirely
2 - terminate processing of this query entirely
*/
*/
bool
sendQuery
=
0
;
bool
sendQuery
=
0
;
bool
querySent
=
0
;
bool
querySent
=
0
;
bool
interactive
;
bool
interactive
;
READ_ROUTINE
GetNextLine
;
READ_ROUTINE
GetNextLine
;
bool
connected
=
1
;
bool
connected
=
1
;
/* We are connected to the backend (last time we looked) */
/* We are connected to the backend (last time we looked) */
bool
eof
=
0
;
bool
eof
=
0
;
/* We've reached the end of our command input. */
/* We've reached the end of our command input. */
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
=
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
strlen
(
PROMPT
)
+
1
);
settings
->
prompt
=
if
(
settings
->
quiet
)
malloc
(
strlen
(
PQdb
(
settings
->
db
))
+
strlen
(
PROMPT
)
+
1
);
settings
->
prompt
[
0
]
=
'\0'
;
if
(
settings
->
quiet
)
else
settings
->
prompt
[
0
]
=
'\0'
;
sprintf
(
settings
->
prompt
,
"%s%s"
,
PQdb
(
settings
->
db
),
PROMPT
);
else
if
(
settings
->
useReadline
)
{
sprintf
(
settings
->
prompt
,
"%s%s"
,
PQdb
(
settings
->
db
),
PROMPT
);
using_history
();
if
(
settings
->
useReadline
)
{
GetNextLine
=
gets_readline
;
using_history
();
}
else
GetNextLine
=
gets_readline
;
GetNextLine
=
gets_noreadline
;
}
else
GetNextLine
=
gets_noreadline
;
}
else
GetNextLine
=
gets_fromFile
;
}
else
query
[
0
]
=
'\0'
;
GetNextLine
=
gets_fromFile
;
query
[
0
]
=
'\0'
;
/* main loop for getting queries and executing them */
/* main loop for getting queries and executing them */
while
(
connected
&&
!
eof
)
{
while
(
connected
&&
!
eof
)
{
line
=
GetNextLine
(
settings
->
prompt
,
source
);
line
=
GetNextLine
(
settings
->
prompt
,
source
);
if
(
line
==
NULL
)
{
/* No more input. Time to quit */
if
(
line
==
NULL
)
{
/* No more input. Time to quit */
printf
(
"EOF
\n
"
);
/* Goes on prompt line */
printf
(
"EOF
\n
"
);
/* Goes on prompt line */
eof
=
1
;
eof
=
true
;
}
else
{
}
else
{
exitStatus
=
0
;
exitStatus
=
0
;
line
=
rightTrim
(
line
);
/* remove whitespaces on the right, incl. \n's */
line
=
rightTrim
(
line
);
/* remove whitespaces on the right, incl. \n's */
if
(
line
[
0
]
==
'\0'
)
{
free
(
line
);
if
(
line
[
0
]
==
'\0'
)
{
continue
;
free
(
line
);
}
continue
;
}
/* filter out comment lines that begin with --,
this could be incorrect if -- is part of a quoted string.
/* filter out comment lines that begin with --,
But we won't go through the trouble of detecting that. If you have
this could be incorrect if -- is part of a quoted string.
-- in your quoted string, be careful and don't start a line with it */
But we won't go through the trouble of detecting that.
if
(
line
[
0
]
==
'-'
&&
line
[
1
]
==
'-'
)
{
If you have -- in your quoted string, be careful and don't
if
(
settings
->
singleStep
)
/* in single step mode, show comments */
start a line with it
fprintf
(
stdout
,
"%s
\n
"
,
line
);
*/
free
(
line
);
if
(
line
[
0
]
==
'-'
&&
line
[
1
]
==
'-'
)
{
continue
;
if
(
settings
->
singleStep
)
}
/* in single step mode, show comments */
if
(
line
[
0
]
!=
'\\'
&&
querySent
)
fprintf
(
stdout
,
"%s
\n
"
,
line
);
{
free
(
line
);
query
[
0
]
=
'\0'
;
continue
;
querySent
=
0
;
}
}
if
(
line
[
0
]
!=
'\\'
&&
querySent
)
{
query
[
0
]
=
'\0'
;
len
=
strlen
(
line
);
querySent
=
0
;
}
if
(
interactive
&&
settings
->
useReadline
)
add_history
(
line
);
/* save non-empty lines in history */
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
/* do the query immediately if we are doing single line queries
or if the last character is a semicolon */
or if the last character is a semicolon
sendQuery
=
settings
->
singleLineMode
||
(
line
[
len
-
1
]
==
';'
)
;
*/
sendQuery
=
settings
->
singleLineMode
||
(
line
[
len
-
1
]
==
';'
)
;
/* normally, \ commands have to be start the line,
but for backwards compatibility with monitor,
/* normally, \ commands have to be start the line,
check for \g at the end of line */
but for backwards compatibility with monitor,
if
(
len
>
2
&&
!
sendQuery
)
check for \g at the end of line */
{
if
(
len
>
2
&&
!
sendQuery
)
{
if
(
line
[
len
-
1
]
==
'g'
&&
line
[
len
-
2
]
==
'\\'
)
if
(
line
[
len
-
1
]
==
'g'
&&
line
[
len
-
2
]
==
'\\'
)
{
{
sendQuery
=
1
;
sendQuery
=
1
;
line
[
len
-
2
]
=
'\0'
;
line
[
len
-
2
]
=
'\0'
;
}
}
}
}
/* slash commands have to be on their own line */
/* slash commands have to be on their own line */
if
(
line
[
0
]
==
'\\'
)
{
if
(
line
[
0
]
==
'\\'
)
{
slashCmdStatus
=
HandleSlashCmds
(
settings
,
slashCmdStatus
=
HandleSlashCmds
(
settings
,
line
,
line
,
query
);
query
);
if
(
slashCmdStatus
==
1
)
{
if
(
slashCmdStatus
==
1
)
{
free
(
line
);
free
(
line
);
continue
;
continue
;
}
}
if
(
slashCmdStatus
==
2
)
{
if
(
slashCmdStatus
==
2
)
{
free
(
line
);
free
(
line
);
break
;
break
;
}
}
if
(
slashCmdStatus
==
0
)
if
(
slashCmdStatus
==
0
)
sendQuery
=
1
;
sendQuery
=
1
;
}
}
else
if
(
strlen
(
query
)
+
len
>
MAX_QUERY_BUFFER
)
{
else
fprintf
(
stderr
,
"query buffer max length of %d exceeded
\n
"
,
if
(
strlen
(
query
)
+
len
>
MAX_QUERY_BUFFER
)
MAX_QUERY_BUFFER
);
{
fprintf
(
stderr
,
"query line ignored
\n
"
);
fprintf
(
stderr
,
"query buffer max length of %d exceeded
\n
"
,
MAX_QUERY_BUFFER
);
}
else
if
(
query
[
0
]
!=
'\0'
)
{
fprintf
(
stderr
,
"query line ignored
\n
"
);
strcat
(
query
,
"
\n
"
);
}
strcat
(
query
,
line
);
else
}
else
strcpy
(
query
,
line
);
if
(
query
[
0
]
!=
'\0'
)
{
if
(
sendQuery
&&
query
[
0
]
!=
'\0'
)
{
strcat
(
query
,
"
\n
"
);
/* echo the line read from the file,
strcat
(
query
,
line
);
unless we are in single_step mode, because single_step mode
}
will echo anyway
else
*/
strcpy
(
query
,
line
);
bool
success
;
/* The query succeeded at the backend */
if
(
sendQuery
&&
query
[
0
]
!=
'\0'
)
if
(
!
interactive
&&
!
settings
->
singleStep
&&
!
settings
->
quiet
)
{
fprintf
(
stderr
,
"%s
\n
"
,
query
);
/* echo the line read from the file,
unless we are in single_step mode, because single_step mode
SendQuery
(
&
success
,
settings
,
query
,
false
,
false
,
0
);
will echo anyway */
exitStatus
=
success
?
0
:
1
;
if
(
!
interactive
&&
!
settings
->
singleStep
&&
!
settings
->
quiet
)
querySent
=
1
;
fprintf
(
stderr
,
"%s
\n
"
,
query
);
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
connected
=
0
;
exitStatus
=
SendQuery
(
settings
,
query
);
fprintf
(
stderr
,
querySent
=
1
;
"We have lost the connection to the backend, so "
if
(
PQstatus
(
settings
->
db
)
==
CONNECTION_BAD
)
{
"further processing is impossible. "
connected
=
0
;
"Terminating.
\n
"
);
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 */
}
}
free
(
line
);
/* free storage malloc'd by GetNextLine */
}
/* while */
}
return
exitStatus
;
}
/* while */
return
exitStatus
;
}
}
int
int
main
(
int
argc
,
char
**
argv
)
main
(
int
argc
,
char
**
argv
)
{
{
...
@@ -1164,26 +1376,26 @@ main(int argc, char **argv)
...
@@ -1164,26 +1376,26 @@ main(int argc, char **argv)
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
;
break
;
case
'd'
:
case
'd'
:
dbname
=
optarg
;
dbname
=
optarg
;
break
;
break
;
...
@@ -1248,92 +1460,89 @@ main(int argc, char **argv)
...
@@ -1248,92 +1460,89 @@ main(int argc, char **argv)
dbname
=
PQdb
(
settings
.
db
);
dbname
=
PQdb
(
settings
.
db
);
if
(
PQstatus
(
settings
.
db
)
==
CONNECTION_BAD
)
{
if
(
PQstatus
(
settings
.
db
)
==
CONNECTION_BAD
)
{
fprintf
(
stderr
,
"Connection to database '%s' failed.
\n
"
,
dbname
);
fprintf
(
stderr
,
"Connection to database '%s' failed.
\n
"
,
dbname
);
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
.
db
));
fprintf
(
stderr
,
"%s"
,
PQerrorMessage
(
settings
.
db
));
exit
(
1
);
exit
(
1
);
}
}
if
(
listDatabases
)
{
if
(
listDatabases
)
{
exit
(
listAllDbs
(
&
settings
));
exit
(
listAllDbs
(
&
settings
));
}
}
if
(
!
settings
.
quiet
&&
!
singleQuery
&&
!
qfilename
)
{
if
(
!
settings
.
quiet
&&
!
singleQuery
&&
!
qfilename
)
{
printf
(
"Welcome to the POSTGRES95 interactive sql monitor:
\n
"
);
printf
(
"Welcome to the POSTGRES95 interactive sql monitor:
\n
"
);
printf
(
" Please read the file COPYRIGHT for copyright terms of POSTGRES95
\n\n
"
);
printf
(
" Please read the file COPYRIGHT for copyright terms "
printf
(
" type
\\
? for help on slash commands
\n
"
);
"of POSTGRES95
\n\n
"
);
printf
(
" type
\\
q to quit
\n
"
);
printf
(
" type
\\
? for help on slash commands
\n
"
);
printf
(
" type
\\
g or terminate with semicolon to execute query
\n
"
);
printf
(
" type
\\
q to quit
\n
"
);
printf
(
" You are currently connected to the database: %s
\n\n
"
,
dbname
);
printf
(
" type
\\
g or terminate with semicolon to execute query
\n
"
);
}
printf
(
" You are currently connected to the database: %s
\n\n
"
,
dbname
);
}
if
(
qfilename
||
singleSlashCmd
)
{
if
(
qfilename
||
singleSlashCmd
)
{
/* read in a file full of queries instead of reading in queries
/* read in a file full of queries instead of reading in queries
interactively */
interactively */
char
*
line
;
char
*
line
;
if
(
singleSlashCmd
)
{
if
(
singleSlashCmd
)
{
/* Not really a query, but "Do what I mean, not what I say." */
/* Not really a query, but "Do what I mean, not what I say." */
line
=
singleQuery
;
line
=
singleQuery
;
}
}
else
{
else
{
line
=
malloc
(
strlen
(
qfilename
)
+
5
);
line
=
malloc
(
strlen
(
qfilename
)
+
5
);
sprintf
(
line
,
"
\\
i %s"
,
qfilename
);
sprintf
(
line
,
"
\\
i %s"
,
qfilename
);
}
}
HandleSlashCmds
(
&
settings
,
line
,
""
);
HandleSlashCmds
(
&
settings
,
line
,
""
);
}
else
{
}
else
{
if
(
singleQuery
)
{
if
(
singleQuery
)
{
bool
success
;
/* The query succeeded at the backend */
exitStatus
=
SendQuery
(
&
settings
,
singleQuery
);
SendQuery
(
&
success
,
&
settings
,
singleQuery
,
false
,
false
,
0
);
}
exitStatus
=
success
?
0
:
1
;
else
}
else
exitStatus
=
MainLoop
(
&
settings
,
stdin
);
exitStatus
=
MainLoop
(
&
settings
,
stdin
);
}
}
PQfinish
(
settings
.
db
);
PQfinish
(
settings
.
db
);
return
exitStatus
;
return
exitStatus
;
}
}
#define COPYBUFSIZ
8192
#define COPYBUFSIZ
8192
static
void
static
void
handleCopyOut
(
PGresult
*
res
,
bool
quiet
)
handleCopyOut
(
PGresult
*
res
,
bool
quiet
,
FILE
*
copystream
)
{
{
bool
copydone
;
bool
copydone
=
false
;
char
copybuf
[
COPYBUFSIZ
];
char
copybuf
[
COPYBUFSIZ
];
int
ret
;
int
ret
;
if
(
!
quiet
)
copydone
=
false
;
/* Can't be done; haven't started. */
fprintf
(
stdout
,
"Copy command returns...
\n
"
);
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
,
stdout
);
fputs
(
copybuf
,
copystream
);
switch
(
ret
)
{
switch
(
ret
)
{
case
EOF
:
case
EOF
:
copydone
=
true
;
copydone
=
true
;
/*FALLTHROUGH*/
/*FALLTHROUGH*/
case
0
:
case
0
:
fputc
(
'\n'
,
stdout
);
fputc
(
'\n'
,
copystream
);
break
;
break
;
case
1
:
case
1
:
break
;
break
;
}
}
}
}
}
}
fflush
(
stdout
);
fflush
(
copystream
);
PQendcopy
(
res
->
conn
);
PQendcopy
(
res
->
conn
);
}
}
static
void
static
void
handleCopyIn
(
PGresult
*
res
,
bool
quiet
)
handleCopyIn
(
PGresult
*
res
,
const
bool
mustprompt
,
FILE
*
copystream
)
{
{
bool
copydone
=
false
;
bool
copydone
=
false
;
bool
firstload
;
bool
firstload
;
bool
linedone
;
bool
linedone
;
...
@@ -1341,56 +1550,49 @@ handleCopyIn(PGresult *res, bool quiet)
...
@@ -1341,56 +1550,49 @@ handleCopyIn(PGresult *res, bool quiet)
char
*
s
;
char
*
s
;
int
buflen
;
int
buflen
;
int
c
;
int
c
;
if
(
!
quiet
)
{
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 period on a line by itself.
\n
"
,
stdout
);
fputs
(
"End with a backslash and a "
"period on a line by itself.
\n
"
,
stdout
);
}
}
/*
while
(
!
copydone
)
{
/* for each input line ... */
* eat extra newline still in input buffer
if
(
mustprompt
)
{
*
fputs
(
">> "
,
stdout
);
*/
fflush
(
stdout
);
fflush
(
stdin
);
if
((
c
=
getc
(
stdin
))
!=
'\n'
&&
c
!=
EOF
)
{
(
void
)
ungetc
(
c
,
stdin
);
}
}
firstload
=
true
;
while
(
!
copydone
)
{
/* for each input line ... */
linedone
=
false
;
if
(
!
quiet
)
{
while
(
!
linedone
)
{
/* for each buffer ... */
fputs
(
">> "
,
stdout
);
s
=
copybuf
;
fflush
(
stdout
);
buflen
=
COPYBUFSIZ
;
}
for
(;
buflen
>
1
&&
firstload
=
true
;
!
(
linedone
=
(
c
=
getc
(
copystream
))
==
'\n'
||
c
==
EOF
);
linedone
=
false
;
--
buflen
)
{
while
(
!
linedone
)
{
/* for each buffer ... */
*
s
++
=
c
;
s
=
copybuf
;
}
buflen
=
COPYBUFSIZ
;
if
(
c
==
EOF
)
{
for
(;
buflen
>
1
&&
PQputline
(
res
->
conn
,
"
\\
."
);
!
(
linedone
=
(
c
=
getc
(
stdin
))
==
'\n'
||
c
==
EOF
);
copydone
=
true
;
--
buflen
)
{
break
;
*
s
++
=
c
;
}
}
*
s
=
'\0'
;
if
(
c
==
EOF
)
{
PQputline
(
res
->
conn
,
copybuf
);
/* reading from stdin, but from a file */
if
(
firstload
)
{
PQputline
(
res
->
conn
,
"
\\
."
);
if
(
!
strcmp
(
copybuf
,
"
\\
."
))
{
copydone
=
true
;
copydone
=
true
;
break
;
}
}
firstload
=
false
;
*
s
=
'\0'
;
}
PQputline
(
res
->
conn
,
copybuf
);
}
if
(
firstload
)
{
PQputline
(
res
->
conn
,
"
\n
"
);
if
(
!
strcmp
(
copybuf
,
"
\\
."
))
{
copydone
=
true
;
}
firstload
=
false
;
}
}
PQputline
(
res
->
conn
,
"
\n
"
);
}
}
PQendcopy
(
res
->
conn
);
PQendcopy
(
res
->
conn
);
}
}
/* try to open fname and return a FILE *,
/* try to open fname and return a FILE *,
if it fails, use stdout, instead */
if it fails, use stdout, instead */
...
@@ -1398,31 +1600,31 @@ FILE *
...
@@ -1398,31 +1600,31 @@ 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
);
signal
(
SIGPIPE
,
SIG_IGN
);
ps
->
queryFout
=
popen
(
fname
+
1
,
"w"
);
ps
->
queryFout
=
popen
(
fname
+
1
,
"w"
);
ps
->
pipe
=
1
;
ps
->
pipe
=
1
;
}
}
else
else
{
{
ps
->
queryFout
=
fopen
(
fname
,
"w"
);
ps
->
queryFout
=
fopen
(
fname
,
"w"
);
ps
->
pipe
=
0
;
ps
->
pipe
=
0
;
}
}
if
(
!
ps
->
queryFout
)
{
if
(
!
ps
->
queryFout
)
{
perror
(
fname
);
perror
(
fname
);
ps
->
queryFout
=
stdout
;
ps
->
queryFout
=
stdout
;
}
}
}
}
return
ps
->
queryFout
;
return
ps
->
queryFout
;
}
}
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