pg 0.8.0-x86-mswin32-60
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/BSD +23 -0
- data/COPYING.txt +340 -0
- data/ChangeLog +261 -0
- data/Contributors +28 -0
- data/GPL +340 -0
- data/LICENSE +58 -0
- data/README +125 -0
- data/Rakefile +103 -0
- data/doc/postgres.html +278 -0
- data/doc/postgres.jp.html +256 -0
- data/ext/compat.c +541 -0
- data/ext/compat.h +180 -0
- data/ext/extconf.rb +87 -0
- data/ext/mingw/Rakefile +24 -0
- data/ext/mingw/build.rake +40 -0
- data/ext/mingw/pg.so +0 -0
- data/ext/mkrf_config.rb +138 -0
- data/ext/pg.c +3569 -0
- data/ext/pg.h +42 -0
- data/ext/vc/pg.sln +26 -0
- data/sample/losample.rb +47 -0
- data/sample/psql.rb +1181 -0
- data/sample/psqlHelp.rb +158 -0
- data/sample/test1.rb +63 -0
- data/sample/test2.rb +44 -0
- data/sample/test4.rb +71 -0
- data/spec/data/expected_trace.out +26 -0
- data/spec/data/random_binary_data +0 -0
- data/spec/pgconn_spec.rb +130 -0
- data/spec/pgresult_spec.rb +112 -0
- metadata +89 -0
data/ext/pg.h
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <sys/types.h>
|
4
|
+
|
5
|
+
#include "ruby.h"
|
6
|
+
#include "libpq-fe.h"
|
7
|
+
#include "libpq/libpq-fs.h" /* large-object interface */
|
8
|
+
|
9
|
+
#include "compat.h"
|
10
|
+
|
11
|
+
#if RUBY_VM != 1
|
12
|
+
#define RUBY_18_COMPAT
|
13
|
+
#endif
|
14
|
+
|
15
|
+
#ifndef RARRAY_LEN
|
16
|
+
#define RARRAY_LEN(x) RARRAY((x))->len
|
17
|
+
#endif /* RARRAY_LEN */
|
18
|
+
|
19
|
+
#ifndef RSTRING_LEN
|
20
|
+
#define RSTRING_LEN(x) RSTRING((x))->len
|
21
|
+
#endif /* RSTRING_LEN */
|
22
|
+
|
23
|
+
#ifndef RSTRING_PTR
|
24
|
+
#define RSTRING_PTR(x) RSTRING((x))->ptr
|
25
|
+
#endif /* RSTRING_PTR */
|
26
|
+
|
27
|
+
#ifndef StringValuePtr
|
28
|
+
#define StringValuePtr(x) STR2CSTR(x)
|
29
|
+
#endif /* StringValuePtr */
|
30
|
+
|
31
|
+
#ifdef RUBY_18_COMPAT
|
32
|
+
#define rb_io_stdio_file GetWriteFile
|
33
|
+
#include "rubyio.h"
|
34
|
+
#else
|
35
|
+
#include "ruby/io.h"
|
36
|
+
#endif
|
37
|
+
|
38
|
+
#if defined(_WIN32)
|
39
|
+
__declspec(dllexport)
|
40
|
+
#endif
|
41
|
+
void Init_pg(void);
|
42
|
+
|
data/ext/vc/pg.sln
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
Microsoft Visual Studio Solution File, Format Version 10.00
|
3
|
+
# Visual Studio 2008
|
4
|
+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pg", "pg_18\pg.vcproj", "{9A8BF0C8-1D75-4DC0-8D84-BAEFD693795E}"
|
5
|
+
EndProject
|
6
|
+
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pg_19", "pg_19\pg_19.vcproj", "{2EE30C74-074F-4611-B39B-38D5F3C9B071}"
|
7
|
+
EndProject
|
8
|
+
Global
|
9
|
+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
10
|
+
Debug|Win32 = Debug|Win32
|
11
|
+
Release|Win32 = Release|Win32
|
12
|
+
EndGlobalSection
|
13
|
+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
14
|
+
{9A8BF0C8-1D75-4DC0-8D84-BAEFD693795E}.Debug|Win32.ActiveCfg = Debug|Win32
|
15
|
+
{9A8BF0C8-1D75-4DC0-8D84-BAEFD693795E}.Debug|Win32.Build.0 = Debug|Win32
|
16
|
+
{9A8BF0C8-1D75-4DC0-8D84-BAEFD693795E}.Release|Win32.ActiveCfg = Release|Win32
|
17
|
+
{9A8BF0C8-1D75-4DC0-8D84-BAEFD693795E}.Release|Win32.Build.0 = Release|Win32
|
18
|
+
{2EE30C74-074F-4611-B39B-38D5F3C9B071}.Debug|Win32.ActiveCfg = Debug|Win32
|
19
|
+
{2EE30C74-074F-4611-B39B-38D5F3C9B071}.Debug|Win32.Build.0 = Debug|Win32
|
20
|
+
{2EE30C74-074F-4611-B39B-38D5F3C9B071}.Release|Win32.ActiveCfg = Release|Win32
|
21
|
+
{2EE30C74-074F-4611-B39B-38D5F3C9B071}.Release|Win32.Build.0 = Release|Win32
|
22
|
+
EndGlobalSection
|
23
|
+
GlobalSection(SolutionProperties) = preSolution
|
24
|
+
HideSolutionNode = FALSE
|
25
|
+
EndGlobalSection
|
26
|
+
EndGlobal
|
data/sample/losample.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require "pg"
|
2
|
+
|
3
|
+
def main
|
4
|
+
conn = PGconn.connect("localhost",5432,"","")
|
5
|
+
puts("dbname: " + conn.db + "\thost: " + conn.host + "\tuser: " + conn.user)
|
6
|
+
|
7
|
+
# Transaction
|
8
|
+
conn.exec("BEGIN")
|
9
|
+
lobj = conn.loimport("losample.rb")
|
10
|
+
lobjnum = lobj.oid
|
11
|
+
puts("loimport ok! oid=" + lobj.oid.to_s)
|
12
|
+
lobj.open
|
13
|
+
lobj.seek(0,PGlarge::SEEK_SET) # SEEK_SET or SEEK_CUR or SEEK_END
|
14
|
+
buff = lobj.read(18)
|
15
|
+
puts buff
|
16
|
+
if 'require "postgres"' == buff
|
17
|
+
puts "read ok!"
|
18
|
+
end
|
19
|
+
lobj.seek(0,PGlarge::SEEK_END)
|
20
|
+
buff = lobj.write("write test ok?\n")
|
21
|
+
puts lobj.tell
|
22
|
+
puts 'export test .file:lowrite.losample add "write test of?"...'
|
23
|
+
lobj.export("lowrite.txt")
|
24
|
+
lobj.close
|
25
|
+
conn.exec("COMMIT")
|
26
|
+
begin
|
27
|
+
lobj.read(1)
|
28
|
+
puts "boo!"
|
29
|
+
return
|
30
|
+
rescue
|
31
|
+
puts "ok! Large Object is closed"
|
32
|
+
end
|
33
|
+
conn.exec("BEGIN")
|
34
|
+
puts lobjnum.to_s
|
35
|
+
lobj = conn.loopen(lobjnum)
|
36
|
+
puts "large object reopen ok!"
|
37
|
+
lobj.seek(0,PGlarge::SEEK_SET) # SEEK_SET or SEEK_CUR or SEEK_END
|
38
|
+
buff = lobj.read(18)
|
39
|
+
puts buff
|
40
|
+
puts "reread ok!"
|
41
|
+
conn.exec("COMMIT")
|
42
|
+
lobj.unlink
|
43
|
+
puts "large object unlink"
|
44
|
+
end
|
45
|
+
|
46
|
+
main
|
47
|
+
|
data/sample/psql.rb
ADDED
@@ -0,0 +1,1181 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# an interactive front-end to postgreSQL
|
4
|
+
#
|
5
|
+
# Original source code is written by C.
|
6
|
+
# Copyright (c) 1996, Regents of the University of California
|
7
|
+
#
|
8
|
+
# ruby version is written by ematsu
|
9
|
+
# Copyright (c) 1997 Eiji-usagi-MATSUmoto <ematsu@pfu.co.jp>
|
10
|
+
#
|
11
|
+
# Changes:
|
12
|
+
#
|
13
|
+
# Fri 12 Dec 19:56:34 JST 1997
|
14
|
+
# * replace puts -> print
|
15
|
+
#
|
16
|
+
# $Id: psql.rb,v 1.1.1.3 2002/04/24 05:46:44 noboru Exp $
|
17
|
+
#
|
18
|
+
|
19
|
+
require "pg"
|
20
|
+
require "parsearg"
|
21
|
+
require "psqlHelp"
|
22
|
+
|
23
|
+
PROMPT = "=> "
|
24
|
+
MAX_QUERY_BUFFER = 20000
|
25
|
+
DEFAULT_SHELL = "/bin/sh"
|
26
|
+
DEFAULT_EDITOR = "vi"
|
27
|
+
DEFAULT_FIELD_SEP= "|"
|
28
|
+
|
29
|
+
PsqlSettings = Struct.new("PsqlSettings", :db, :queryFout, :opt, :prompt,
|
30
|
+
:gfname, :notty,:pipe, :echoQuery,:quiet,
|
31
|
+
:singleStep, :singleLineMode, :useReadline)
|
32
|
+
|
33
|
+
PrintOpt = Struct.new("PrintOpt", :header, :align, :standard, :html3,
|
34
|
+
:expanded, :pager, :fieldSep, :tableOpt,
|
35
|
+
:caption, :fieldName)
|
36
|
+
|
37
|
+
$readline_ok = TRUE
|
38
|
+
|
39
|
+
def usage()
|
40
|
+
printf("Usage: psql.rb [options] [dbname]\n")
|
41
|
+
printf("\t -a authsvc set authentication service\n")
|
42
|
+
printf("\t -A turn off alignment when printing out attributes\n")
|
43
|
+
printf("\t -c query run single query (slash commands too)\n")
|
44
|
+
printf("\t -d dbName specify database name\n")
|
45
|
+
printf("\t -e echo the query sent to the backend\n")
|
46
|
+
printf("\t -f filename use file as a source of queries\n")
|
47
|
+
printf("\t -F sep set the field separator (default is \" \")\n")
|
48
|
+
printf("\t -h host set database server host\n")
|
49
|
+
printf("\t -H turn on html3.0 table output\n")
|
50
|
+
printf("\t -l list available databases\n")
|
51
|
+
printf("\t -n don't use readline library\n")
|
52
|
+
printf("\t -o filename send output to filename or (|pipe)\n")
|
53
|
+
printf("\t -p port set port number\n")
|
54
|
+
printf("\t -q run quietly (no messages, no prompts)\n")
|
55
|
+
printf("\t -s single step mode (prompts for each query)\n")
|
56
|
+
printf("\t -S single line mode (i.e. query terminated by newline)\n")
|
57
|
+
printf("\t -t turn off printing of headings and row count\n")
|
58
|
+
printf("\t -T html set html3.0 table command options (cf. -H)\n")
|
59
|
+
printf("\t -x turn on expanded output (field names on left)\n")
|
60
|
+
exit(1)
|
61
|
+
end
|
62
|
+
$USAGE = 'usage'
|
63
|
+
|
64
|
+
def slashUsage(ps)
|
65
|
+
printf(" \\? -- help\n")
|
66
|
+
printf(" \\a -- toggle field-alignment (currenty %s)\n", on(ps.opt.align))
|
67
|
+
printf(" \\C [<captn>] -- set html3 caption (currently '%s')\n", ps.opt.caption );
|
68
|
+
printf(" \\connect <dbname> -- connect to new database (currently '%s')\n", ps.db.db)
|
69
|
+
printf(" \\copy {<table> to <file> | <file> from <table>}\n")
|
70
|
+
printf(" \\d [<table>] -- list tables in database or columns in <table>, * for all\n")
|
71
|
+
printf(" \\da -- list aggregates\n")
|
72
|
+
printf(" \\di -- list only indices\n")
|
73
|
+
printf(" \\ds -- list only sequences\n")
|
74
|
+
printf(" \\dS -- list system tables and indexes\n")
|
75
|
+
printf(" \\dt -- list only tables\n")
|
76
|
+
printf(" \\dT -- list types\n")
|
77
|
+
printf(" \\e [<fname>] -- edit the current query buffer or <fname>\n")
|
78
|
+
printf(" \\E [<fname>] -- edit the current query buffer or <fname>, and execute\n")
|
79
|
+
printf(" \\f [<sep>] -- change field separater (currently '%s')\n", ps.opt.fieldSep)
|
80
|
+
printf(" \\g [<fname>] [|<cmd>] -- send query to backend [and results in <fname> or pipe]\n")
|
81
|
+
printf(" \\h [<cmd>] -- help on syntax of sql commands, * for all commands\n")
|
82
|
+
printf(" \\H -- toggle html3 output (currently %s)\n", on(ps.opt.html3))
|
83
|
+
printf(" \\i <fname> -- read and execute queries from filename\n")
|
84
|
+
printf(" \\l -- list all databases\n")
|
85
|
+
printf(" \\m -- toggle monitor-like table display (currently %s)\n", on(ps.opt.standard))
|
86
|
+
printf(" \\o [<fname>] [|<cmd>] -- send all query results to stdout, <fname>, or pipe\n")
|
87
|
+
printf(" \\p -- print the current query buffer\n")
|
88
|
+
printf(" \\q -- quit\n")
|
89
|
+
printf(" \\r -- reset(clear) the query buffer\n")
|
90
|
+
printf(" \\s [<fname>] -- print history or save it in <fname>\n")
|
91
|
+
printf(" \\t -- toggle table headings and row count (currently %s)\n", on(ps.opt.header))
|
92
|
+
printf(" \\T [<html>] -- set html3.0 <table ...> options (currently '%s')\n", ps.opt.tableOpt)
|
93
|
+
printf(" \\x -- toggle expanded output (currently %s)\n", on(ps.opt.expanded))
|
94
|
+
printf(" \\! [<cmd>] -- shell escape or command\n")
|
95
|
+
end
|
96
|
+
|
97
|
+
def on(f)
|
98
|
+
if f
|
99
|
+
return "on"
|
100
|
+
else
|
101
|
+
return "off"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def toggle(settings, sw, msg)
|
106
|
+
sw = !sw
|
107
|
+
if !settings.quiet
|
108
|
+
printf(STDERR, "turned %s %s\n", on(sw), msg)
|
109
|
+
end
|
110
|
+
return sw
|
111
|
+
end
|
112
|
+
|
113
|
+
def gets(prompt, source)
|
114
|
+
if source == STDIN
|
115
|
+
if ($readline_ok)
|
116
|
+
line = Readline.readline(prompt,source)
|
117
|
+
else
|
118
|
+
STDOUT.print(prompt)
|
119
|
+
STDOUT.flush()
|
120
|
+
line = source.gets
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
if line == nil
|
125
|
+
return nil
|
126
|
+
else
|
127
|
+
if line.length > MAX_QUERY_BUFFER
|
128
|
+
printf(STDERR, "line read exceeds maximum length. Truncating at %d\n",
|
129
|
+
MAX_QUERY_BUFFER)
|
130
|
+
return line[0..MAX_QUERY_BUFFER-1]
|
131
|
+
else
|
132
|
+
return line
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def PSQLexec(ps, query)
|
138
|
+
res = ps.db.exec(query)
|
139
|
+
|
140
|
+
if res == nil
|
141
|
+
printf(STDERR, "%s\n", ps.db.error())
|
142
|
+
|
143
|
+
else
|
144
|
+
if (res.status() == PGresult::COMMAND_OK ||
|
145
|
+
res.status() == PGresult::TUPLES_OK)
|
146
|
+
return res
|
147
|
+
end
|
148
|
+
|
149
|
+
if !ps.quiet
|
150
|
+
printf(STDERR, "%s\n", ps.db.error())
|
151
|
+
end
|
152
|
+
|
153
|
+
res.clear()
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
def listAllDbs(ps)
|
159
|
+
query = "select * from pg_database;"
|
160
|
+
|
161
|
+
if (results = PSQLexec(ps, query)) == nil
|
162
|
+
return 1
|
163
|
+
|
164
|
+
else
|
165
|
+
results.print(ps.queryFout, ps.opt)
|
166
|
+
results.clear()
|
167
|
+
return 0
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
def tableList(ps, deep_tablelist, info_type, system_tables)
|
172
|
+
listbuf = "SELECT usename, relname, relkind, relhasrules"
|
173
|
+
listbuf += " FROM pg_class, pg_user "
|
174
|
+
listbuf += "WHERE usesysid = relowner "
|
175
|
+
case info_type
|
176
|
+
when 't'
|
177
|
+
listbuf += "and ( relkind = 'r') "
|
178
|
+
when 'i'
|
179
|
+
listbuf += "and ( relkind = 'i') "
|
180
|
+
haveIndexes = true
|
181
|
+
when 'S'
|
182
|
+
listbuf += "and ( relkind = 'S') "
|
183
|
+
else
|
184
|
+
listbuf += "and ( relkind = 'r' OR relkind = 'i' OR relkind='S') "
|
185
|
+
haveIndexes = true
|
186
|
+
end
|
187
|
+
if (!system_tables)
|
188
|
+
listbuf += "and relname !~ '^pg_' "
|
189
|
+
else
|
190
|
+
listbuf += "and relname ~ '^pg_' "
|
191
|
+
end
|
192
|
+
if (haveIndexes)
|
193
|
+
listbuf += "and (relkind != 'i' OR relname !~'^xinx')"
|
194
|
+
end
|
195
|
+
listbuf += " ORDER BY relname "
|
196
|
+
|
197
|
+
res = PSQLexec(ps, listbuf)
|
198
|
+
if res == nil
|
199
|
+
return
|
200
|
+
end
|
201
|
+
|
202
|
+
# first, print out the attribute names
|
203
|
+
nColumns = res.num_tuples
|
204
|
+
if nColumns > 0
|
205
|
+
if deep_tablelist
|
206
|
+
table = res.result
|
207
|
+
res.clear
|
208
|
+
for i in 0..nColumns-1
|
209
|
+
tableDesc(ps, table[i][1])
|
210
|
+
end
|
211
|
+
else
|
212
|
+
# Display the information
|
213
|
+
|
214
|
+
printf("\nDatabase = %s\n", ps.db.db)
|
215
|
+
printf(" +------------------+----------------------------------+----------+\n")
|
216
|
+
printf(" | Owner | Relation | Type |\n")
|
217
|
+
printf(" +------------------+----------------------------------+----------+\n")
|
218
|
+
|
219
|
+
# next, print out the instances
|
220
|
+
for i in 0..res.num_tuples-1
|
221
|
+
printf(" | %-16.16s", res.getvalue(i, 0))
|
222
|
+
printf(" | %-32.32s | ", res.getvalue(i, 1))
|
223
|
+
rk = res.getvalue(i, 2)
|
224
|
+
rr = res.getvalue(i, 3)
|
225
|
+
if (rk.eql?("r"))
|
226
|
+
printf("%-8.8s |", if (rr[0] == 't') then "view?" else "table" end)
|
227
|
+
else
|
228
|
+
printf("%-8.8s |", "index")
|
229
|
+
end
|
230
|
+
printf("\n")
|
231
|
+
end
|
232
|
+
printf(" +------------------+----------------------------------+----------+\n")
|
233
|
+
res.clear()
|
234
|
+
end
|
235
|
+
else
|
236
|
+
printf(STDERR, "Couldn't find any tables!\n")
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def tableDesc(ps, table)
|
241
|
+
descbuf = "SELECT a.attnum, a.attname, t.typname, a.attlen"
|
242
|
+
descbuf += " FROM pg_class c, pg_attribute a, pg_type t "
|
243
|
+
descbuf += " WHERE c.relname = '"
|
244
|
+
descbuf += table
|
245
|
+
descbuf += "'"
|
246
|
+
descbuf += " and a.attnum > 0 "
|
247
|
+
descbuf += " and a.attrelid = c.oid "
|
248
|
+
descbuf += " and a.atttypid = t.oid "
|
249
|
+
descbuf += " ORDER BY attnum "
|
250
|
+
|
251
|
+
res = PSQLexec(ps, descbuf)
|
252
|
+
if res == nil
|
253
|
+
return
|
254
|
+
end
|
255
|
+
|
256
|
+
# first, print out the attribute names
|
257
|
+
nColumns = res.num_tuples()
|
258
|
+
if nColumns > 0
|
259
|
+
#
|
260
|
+
# Display the information
|
261
|
+
#
|
262
|
+
|
263
|
+
printf("\nTable = %s\n", table)
|
264
|
+
printf("+----------------------------------+----------------------------------+-------+\n")
|
265
|
+
printf("| Field | Type | Length|\n")
|
266
|
+
printf("+----------------------------------+----------------------------------+-------+\n")
|
267
|
+
|
268
|
+
# next, print out the instances
|
269
|
+
for i in 0..res.num_tuples-1
|
270
|
+
|
271
|
+
printf("| %-32.32s | ", res.getvalue(i, 1))
|
272
|
+
rtype = res.getvalue(i, 2);
|
273
|
+
rsize = res.getvalue(i, 3).to_i
|
274
|
+
|
275
|
+
if (rtype.eql?("text"))
|
276
|
+
printf("%-32.32s |", rtype)
|
277
|
+
printf("%6s |", "var")
|
278
|
+
elsif (rtype.eql?("bpchar"))
|
279
|
+
printf("%-32.32s |", "(bp)char")
|
280
|
+
printf("%6i |", if (rsize > 0) then rsize - 4 else 0 end)
|
281
|
+
elsif (rtype.eql?("varchar"))
|
282
|
+
printf("%-32.32s |", rtype)
|
283
|
+
printf("%6d |", if (rsize > 0) then rsize - 4 else 0 end)
|
284
|
+
else
|
285
|
+
# array types start with an underscore
|
286
|
+
if (rtype[0, 1] != '_')
|
287
|
+
printf("%-32.32s |", rtype)
|
288
|
+
else
|
289
|
+
newname = rtype + "[]"
|
290
|
+
printf("%-32.32s |", newname)
|
291
|
+
end
|
292
|
+
if (rsize > 0)
|
293
|
+
printf("%6d |", rsize)
|
294
|
+
else
|
295
|
+
printf("%6s |", "var")
|
296
|
+
end
|
297
|
+
end
|
298
|
+
printf("\n")
|
299
|
+
end
|
300
|
+
printf("+----------------------------------+----------------------------------+-------+\n")
|
301
|
+
|
302
|
+
res.clear()
|
303
|
+
|
304
|
+
else
|
305
|
+
printf(STDERR, "Couldn't find table %s!\n", table)
|
306
|
+
end
|
307
|
+
end
|
308
|
+
|
309
|
+
def unescape(source)
|
310
|
+
dest = source.gsub(/(\\n|\\r|\\t|\\f|\\\\)/) {
|
311
|
+
|c|
|
312
|
+
case c
|
313
|
+
when "\\n"
|
314
|
+
"\n"
|
315
|
+
when "\\r"
|
316
|
+
"\r"
|
317
|
+
when "\\t"
|
318
|
+
"\t"
|
319
|
+
when "\\f"
|
320
|
+
"\f"
|
321
|
+
when "\\\\"
|
322
|
+
"\\"
|
323
|
+
end
|
324
|
+
}
|
325
|
+
return dest
|
326
|
+
end
|
327
|
+
|
328
|
+
def do_shell(command)
|
329
|
+
if !command
|
330
|
+
command = ENV["SHELL"]
|
331
|
+
if shellName == nil
|
332
|
+
command = DEFAULT_SHELL
|
333
|
+
end
|
334
|
+
end
|
335
|
+
system(command);
|
336
|
+
end
|
337
|
+
|
338
|
+
def do_help(topic)
|
339
|
+
if !topic
|
340
|
+
printf("type \\h <cmd> where <cmd> is one of the following:\n")
|
341
|
+
|
342
|
+
left_center_right = 'L' # Start with left column
|
343
|
+
for i in 0..QL_HELP.length-1
|
344
|
+
case left_center_right
|
345
|
+
when 'L'
|
346
|
+
printf(" %-25s", QL_HELP[i][0])
|
347
|
+
left_center_right = 'C'
|
348
|
+
|
349
|
+
when 'C'
|
350
|
+
printf("%-25s", QL_HELP[i][0])
|
351
|
+
left_center_right = 'R'
|
352
|
+
|
353
|
+
when 'R'
|
354
|
+
printf("%-25s\n", QL_HELP[i][0])
|
355
|
+
left_center_right = 'L'
|
356
|
+
|
357
|
+
end
|
358
|
+
end
|
359
|
+
if (left_center_right != 'L')
|
360
|
+
STDOUT.print("\n")
|
361
|
+
end
|
362
|
+
printf("type \\h * for a complete description of all commands\n")
|
363
|
+
else
|
364
|
+
help_found = FALSE
|
365
|
+
for i in 0..QL_HELP.length-1
|
366
|
+
if QL_HELP[i][0] == topic || topic == "*"
|
367
|
+
help_found = TRUE
|
368
|
+
printf("Command: %s\n", QL_HELP[i][0])
|
369
|
+
printf("Description: %s\n", QL_HELP[i][1])
|
370
|
+
printf("Syntax:\n")
|
371
|
+
printf("%s\n", QL_HELP[i][2])
|
372
|
+
printf("\n")
|
373
|
+
end
|
374
|
+
end
|
375
|
+
if !help_found
|
376
|
+
printf("command not found, ")
|
377
|
+
printf("try \\h with no arguments to see available help\n")
|
378
|
+
end
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def do_edit(filename_arg, query)
|
383
|
+
if filename_arg
|
384
|
+
fname = filename_arg
|
385
|
+
error = FALSE
|
386
|
+
else
|
387
|
+
fname = sprintf("/tmp/psql.rb.%d", $$)
|
388
|
+
p fname
|
389
|
+
if test(?e, fname)
|
390
|
+
File.unlink(fname)
|
391
|
+
end
|
392
|
+
|
393
|
+
if query
|
394
|
+
begin
|
395
|
+
fd = File.new(fname, "w")
|
396
|
+
if query[query.length-1, 1] != "\n"
|
397
|
+
query += "\n"
|
398
|
+
end
|
399
|
+
if fd.print(query) != query.length
|
400
|
+
fd.close
|
401
|
+
File.unlink(fname)
|
402
|
+
error = TRUE
|
403
|
+
else
|
404
|
+
error = FALSE
|
405
|
+
end
|
406
|
+
fd.close
|
407
|
+
rescue
|
408
|
+
error = TRUE
|
409
|
+
end
|
410
|
+
else
|
411
|
+
error = FALSE
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
if error
|
416
|
+
status = 1
|
417
|
+
else
|
418
|
+
editFile(fname)
|
419
|
+
begin
|
420
|
+
fd = File.new(fname, "r")
|
421
|
+
query = fd.read
|
422
|
+
fd.close
|
423
|
+
if query == nil
|
424
|
+
status = 1
|
425
|
+
else
|
426
|
+
query.sub!(/[ \t\f\r\n]*$/, "")
|
427
|
+
if query.length != 0
|
428
|
+
status = 3
|
429
|
+
else
|
430
|
+
query = nil
|
431
|
+
status = 1
|
432
|
+
end
|
433
|
+
end
|
434
|
+
rescue
|
435
|
+
status = 1
|
436
|
+
ensure
|
437
|
+
if !filename_arg
|
438
|
+
if test(?e, fname)
|
439
|
+
File.unlink(fname)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
return status, query
|
445
|
+
end
|
446
|
+
|
447
|
+
def editFile(fname)
|
448
|
+
editorName = ENV["EDITOR"]
|
449
|
+
if editorName == nil
|
450
|
+
editorName = DEFAULT_EDITOR
|
451
|
+
end
|
452
|
+
system(editorName + " " + fname)
|
453
|
+
end
|
454
|
+
|
455
|
+
def do_connect(settings, new_dbname)
|
456
|
+
dbname = settings.db.db
|
457
|
+
|
458
|
+
if !new_dbname
|
459
|
+
printf(STDERR, "\\connect must be followed by a database name\n");
|
460
|
+
else
|
461
|
+
olddb = settings.db
|
462
|
+
|
463
|
+
begin
|
464
|
+
printf("closing connection to database: %s\n", dbname);
|
465
|
+
settings.db = PGconn.connect(olddb.host, olddb.port, "", "", new_dbname)
|
466
|
+
printf("connecting to new database: %s\n", new_dbname)
|
467
|
+
olddb.finish()
|
468
|
+
rescue
|
469
|
+
printf(STDERR, "%s\n", $!)
|
470
|
+
printf("reconnecting to %s\n", dbname)
|
471
|
+
settings.db = PGconn.connect(olddb.host, olddb.port,"", "", dbname)
|
472
|
+
ensure
|
473
|
+
settings.prompt = settings.db.db + PROMPT
|
474
|
+
end
|
475
|
+
end
|
476
|
+
end
|
477
|
+
|
478
|
+
def do_copy(settings, table, from_p, file)
|
479
|
+
if (table == nil || from_p == nil || file == nil)
|
480
|
+
printf("Syntax error, reffer \\copy help with \\? \n")
|
481
|
+
return
|
482
|
+
end
|
483
|
+
|
484
|
+
if from_p.upcase! == "FROM"
|
485
|
+
from = TRUE
|
486
|
+
else
|
487
|
+
from = FALSE
|
488
|
+
end
|
489
|
+
|
490
|
+
query = "COPY "
|
491
|
+
query += table
|
492
|
+
|
493
|
+
if from
|
494
|
+
query += " FROM stdin"
|
495
|
+
copystream = File.new(file, "r")
|
496
|
+
else
|
497
|
+
query += " TO stdout"
|
498
|
+
copystream = File.new(file, "w")
|
499
|
+
end
|
500
|
+
|
501
|
+
begin
|
502
|
+
success = SendQuery(settings, query, from, !from, copystream);
|
503
|
+
copystream.close
|
504
|
+
if !settings.quiet
|
505
|
+
if success
|
506
|
+
printf("Successfully copied.\n");
|
507
|
+
else
|
508
|
+
printf("Copy failed.\n");
|
509
|
+
end
|
510
|
+
end
|
511
|
+
rescue
|
512
|
+
printf(STDERR, "Unable to open file %s which to copy.",
|
513
|
+
if from then "from" else "to" end)
|
514
|
+
end
|
515
|
+
end
|
516
|
+
|
517
|
+
def handleCopyOut(settings, copystream)
|
518
|
+
copydone = FALSE
|
519
|
+
|
520
|
+
while !copydone
|
521
|
+
copybuf = settings.db.getline
|
522
|
+
|
523
|
+
if !copybuf
|
524
|
+
copydone = TRUE
|
525
|
+
else
|
526
|
+
if copybuf == "\\."
|
527
|
+
copydone = TRUE
|
528
|
+
else
|
529
|
+
copystream.print(copybuf + "\n")
|
530
|
+
end
|
531
|
+
end
|
532
|
+
end
|
533
|
+
copystream.flush
|
534
|
+
settings.db.endcopy
|
535
|
+
end
|
536
|
+
|
537
|
+
def handleCopyIn(settings, mustprompt, copystream)
|
538
|
+
copydone = FALSE
|
539
|
+
|
540
|
+
if mustprompt
|
541
|
+
STDOUT.print("Enter info followed by a newline\n")
|
542
|
+
STDOUT.print("End with a backslash and a ")
|
543
|
+
STDOUT.print("period on a line by itself.\n")
|
544
|
+
end
|
545
|
+
|
546
|
+
while !copydone
|
547
|
+
if mustprompt
|
548
|
+
STDOUT.print(">> ")
|
549
|
+
STDOUT.flush
|
550
|
+
end
|
551
|
+
|
552
|
+
copybuf = copystream.gets
|
553
|
+
if copybuf == nil
|
554
|
+
settings.db.putline("\\.\n")
|
555
|
+
copydone = TRUE
|
556
|
+
break
|
557
|
+
end
|
558
|
+
settings.db.putline(copybuf)
|
559
|
+
if copybuf == "\\.\n"
|
560
|
+
copydone = TRUE
|
561
|
+
end
|
562
|
+
end
|
563
|
+
settings.db.endcopy
|
564
|
+
end
|
565
|
+
|
566
|
+
def setFout(ps, fname)
|
567
|
+
if (ps.queryFout && ps.queryFout != STDOUT)
|
568
|
+
ps.queryFout.close
|
569
|
+
end
|
570
|
+
|
571
|
+
if !fname
|
572
|
+
ps.queryFout = STDOUT
|
573
|
+
else
|
574
|
+
begin
|
575
|
+
if fname[0, 1] == "|"
|
576
|
+
dumy, ps.queryFout = pipe(fname)
|
577
|
+
ps.pipe = TRUE
|
578
|
+
else
|
579
|
+
ps.queryFout = File.new(fname, "w+")
|
580
|
+
ps.pipe = FALSE
|
581
|
+
end
|
582
|
+
rescue
|
583
|
+
ps.queryFout = STDOUT
|
584
|
+
ps.pipe = FALSE
|
585
|
+
end
|
586
|
+
end
|
587
|
+
end
|
588
|
+
|
589
|
+
def HandleSlashCmds(settings, line, query)
|
590
|
+
status = 1
|
591
|
+
cmd = unescape(line[1, line.length])
|
592
|
+
args = cmd.split
|
593
|
+
|
594
|
+
case args[0]
|
595
|
+
when 'a' # toggles to align fields on output
|
596
|
+
settings.opt.align =
|
597
|
+
toggle(settings, settings.opt.align, "field alignment")
|
598
|
+
|
599
|
+
when 'C' # define new caption
|
600
|
+
if !args[1]
|
601
|
+
settings.opt.caption = ""
|
602
|
+
else
|
603
|
+
settings.opt.caption = args[1]
|
604
|
+
end
|
605
|
+
|
606
|
+
when 'c', 'connect' # connect new database
|
607
|
+
do_connect(settings, args[1])
|
608
|
+
|
609
|
+
when 'copy' # copy from file
|
610
|
+
do_copy(settings, args[1], args[2], args[3])
|
611
|
+
|
612
|
+
when 'd' # \d describe tables or columns in a table
|
613
|
+
if !args[1]
|
614
|
+
tableList(settings, FALSE, 'b', FALSE)
|
615
|
+
elsif args[1] == "*"
|
616
|
+
tableList(settings, FALSE, 'b', FALSE)
|
617
|
+
tableList(settings, TRUE, 'b', FALSE)
|
618
|
+
else
|
619
|
+
tableDesc(settings, args[1])
|
620
|
+
end
|
621
|
+
|
622
|
+
when 'da'
|
623
|
+
descbuf = "SELECT a.aggname AS aggname, t.typname AS type, "
|
624
|
+
descbuf += "obj_description (a.oid) as description "
|
625
|
+
descbuf += "FROM pg_aggregate a, pg_type t "
|
626
|
+
descbuf += "WHERE a.aggbasetype = t.oid "
|
627
|
+
if (args[1])
|
628
|
+
descbuf += "AND a.aggname ~ '^"
|
629
|
+
descbuf += args[1]
|
630
|
+
descbuf += "' "
|
631
|
+
end
|
632
|
+
descbuf += "UNION SELECT a.aggname AS aggname, "
|
633
|
+
descbuf += "'all types' as type, obj_description (a.oid) "
|
634
|
+
descbuf += "as description FROM pg_aggregate a "
|
635
|
+
descbuf += "WHERE a.aggbasetype = 0"
|
636
|
+
if (args[1])
|
637
|
+
descbuf += "AND a.aggname ~ '^"
|
638
|
+
descbuf += args[1]
|
639
|
+
descbuf += "' "
|
640
|
+
end
|
641
|
+
descbuf += "ORDER BY aggname, type;"
|
642
|
+
res = SendQuery(settings, descbuf, FALSE, FALSE, 0)
|
643
|
+
|
644
|
+
when 'di'
|
645
|
+
tableList(settings, FALSE, 'i', FALSE)
|
646
|
+
|
647
|
+
when 'ds'
|
648
|
+
tableList(settings, FALSE, 'S', FALSE)
|
649
|
+
|
650
|
+
when 'dS'
|
651
|
+
tableList(settings, FALSE, 'b', TRUE)
|
652
|
+
|
653
|
+
when 'dt'
|
654
|
+
tableList(settings, FALSE, 't', FALSE)
|
655
|
+
|
656
|
+
when 'e' # edit
|
657
|
+
status, query = do_edit(args[1], query)
|
658
|
+
|
659
|
+
when 'E'
|
660
|
+
if args[1]
|
661
|
+
begin
|
662
|
+
lastfile = args[1]
|
663
|
+
File.file?(lastfile) && (mt = File.mtime(lastfile))
|
664
|
+
editFile(lastfile)
|
665
|
+
File.file?(lastfile) && (mt2 = File.mtime(lastfile))
|
666
|
+
fd = File.new(lastfile, "r")
|
667
|
+
if mt != mt2
|
668
|
+
MainLoop(settings, fd)
|
669
|
+
fd.close()
|
670
|
+
else
|
671
|
+
if !settings.quiet
|
672
|
+
printf(STDERR, "warning: %s not modified. query not executed\n", lastfile)
|
673
|
+
end
|
674
|
+
fd.close()
|
675
|
+
end
|
676
|
+
rescue
|
677
|
+
#
|
678
|
+
end
|
679
|
+
else
|
680
|
+
printf(STDERR, "\\r must be followed by a file name initially\n");
|
681
|
+
end
|
682
|
+
when 'f'
|
683
|
+
if args[1]
|
684
|
+
settings.opt.fieldSep = args[1]
|
685
|
+
if !settings.quiet
|
686
|
+
printf(STDERR, "field separater changed to '%s'\n", settings.opt.fieldSep)
|
687
|
+
end
|
688
|
+
end
|
689
|
+
|
690
|
+
when 'g' # \g means send query
|
691
|
+
if !args[1]
|
692
|
+
settings.gfname = nil
|
693
|
+
else
|
694
|
+
settings.gfname = args[1]
|
695
|
+
end
|
696
|
+
status = 0
|
697
|
+
|
698
|
+
when 'h' # help
|
699
|
+
if args[2]
|
700
|
+
args[1] += " " + args[2]
|
701
|
+
end
|
702
|
+
do_help(args[1])
|
703
|
+
|
704
|
+
when 'i' # \i is include file
|
705
|
+
if args[1]
|
706
|
+
begin
|
707
|
+
fd = File.open(args[1], "r")
|
708
|
+
MainLoop(settings, fd)
|
709
|
+
fd.close()
|
710
|
+
rescue Errno::ENOENT
|
711
|
+
printf(STDERR, "file named %s could not be opened\n", args[1])
|
712
|
+
end
|
713
|
+
else
|
714
|
+
printf(STDERR, "\\i must be followed by a file name\n")
|
715
|
+
end
|
716
|
+
when 'l' # \l is list database
|
717
|
+
listAllDbs(settings)
|
718
|
+
|
719
|
+
when 'H'
|
720
|
+
settings.opt.html3 =
|
721
|
+
toggle(settings, settings.opt.html3, "HTML3.0 tabular output")
|
722
|
+
|
723
|
+
if settings.opt.html3
|
724
|
+
settings.opt.standard = FALSE
|
725
|
+
end
|
726
|
+
|
727
|
+
when 'o'
|
728
|
+
setFout(settings, args[1])
|
729
|
+
|
730
|
+
when 'p'
|
731
|
+
if query
|
732
|
+
File.print(query)
|
733
|
+
File.print("\n")
|
734
|
+
end
|
735
|
+
|
736
|
+
when 'q' # \q is quit
|
737
|
+
status = 2
|
738
|
+
|
739
|
+
when 'r' # reset(clear) the buffer
|
740
|
+
query = nil
|
741
|
+
if !settings.quiet
|
742
|
+
printf(STDERR, "buffer reset(cleared)\n")
|
743
|
+
end
|
744
|
+
|
745
|
+
when 's' # \s is save history to a file
|
746
|
+
begin
|
747
|
+
if (args[1])
|
748
|
+
fd = File.open(args[1], "w")
|
749
|
+
else
|
750
|
+
fd = STDOUT
|
751
|
+
end
|
752
|
+
Readline::HISTORY.each do |his|
|
753
|
+
fd.write (his + "\n")
|
754
|
+
end
|
755
|
+
if !fd.tty?
|
756
|
+
begin
|
757
|
+
fd.close
|
758
|
+
end
|
759
|
+
end
|
760
|
+
rescue
|
761
|
+
printf(STDERR, "cannot write history \n");
|
762
|
+
end
|
763
|
+
|
764
|
+
when 'm' # monitor like type-setting
|
765
|
+
settings.opt.standard =
|
766
|
+
toggle(settings, settings.opt.standard, "standard SQL separaters and padding")
|
767
|
+
if settings.opt.standard
|
768
|
+
settings.opt.html3 = FALSE
|
769
|
+
settings.opt.expanded = FALSE
|
770
|
+
settings.opt.align = TRUE
|
771
|
+
settings.opt.header = TRUE
|
772
|
+
if settings.opt.fieldSep
|
773
|
+
settings.opt.fieldSep = ""
|
774
|
+
end
|
775
|
+
settings.opt.fieldSep = "|"
|
776
|
+
if !settings.quiet
|
777
|
+
printf(STDERR, "field separater changed to '%s'\n", settings.opt.fieldSep)
|
778
|
+
end
|
779
|
+
else
|
780
|
+
if settings.opt.fieldSep
|
781
|
+
settings.opt.fieldSep = ""
|
782
|
+
end
|
783
|
+
settings.opt.fieldSep = DEFAULT_FIELD_SEP
|
784
|
+
if !settings.quiet
|
785
|
+
printf(STDERR, "field separater changed to '%s'\n", settings.opt.fieldSep)
|
786
|
+
end
|
787
|
+
end
|
788
|
+
|
789
|
+
when 't' # toggle headers
|
790
|
+
settings.opt.header =
|
791
|
+
toggle(settings, settings.opt.header, "output headings and row count")
|
792
|
+
|
793
|
+
when 'T' # define html <table ...> option
|
794
|
+
if !args[1]
|
795
|
+
settings.opt.tableOpt = nil
|
796
|
+
else
|
797
|
+
settings.opt.tableOpt = args[1]
|
798
|
+
end
|
799
|
+
|
800
|
+
when 'x'
|
801
|
+
settings.opt.expanded =
|
802
|
+
toggle(settings, settings.opt.expanded, "expanded table representation")
|
803
|
+
|
804
|
+
when '!'
|
805
|
+
do_shell(args[1])
|
806
|
+
|
807
|
+
when '?' # \? is help
|
808
|
+
slashUsage(settings)
|
809
|
+
end
|
810
|
+
|
811
|
+
return status, query
|
812
|
+
end
|
813
|
+
|
814
|
+
def SendQuery(settings, query, copy_in, copy_out, copystream)
|
815
|
+
if settings.singleStep
|
816
|
+
printf("\n**************************************")
|
817
|
+
printf("*****************************************\n")
|
818
|
+
end
|
819
|
+
|
820
|
+
if (settings.echoQuery || settings.singleStep)
|
821
|
+
printf(STDERR, "QUERY: %s\n", query);
|
822
|
+
end
|
823
|
+
|
824
|
+
if settings.singleStep
|
825
|
+
printf("\n**************************************");
|
826
|
+
printf("*****************************************\n")
|
827
|
+
STDOUT.flush
|
828
|
+
printf("\npress return to continue ..\n");
|
829
|
+
gets("", STDIN);
|
830
|
+
end
|
831
|
+
|
832
|
+
begin
|
833
|
+
results = settings.db.exec(query)
|
834
|
+
case results.status
|
835
|
+
when PGresult::TUPLES_OK
|
836
|
+
success = TRUE
|
837
|
+
if settings.gfname
|
838
|
+
setFout(settings, settings.gfname)
|
839
|
+
settings.gfname = nil
|
840
|
+
results.print(settings.queryFout, settings.opt)
|
841
|
+
settings.queryFout.flush
|
842
|
+
if settings.queryFout != STDOUT
|
843
|
+
settings.queryFout.close
|
844
|
+
settings.queryFout = STDOUT
|
845
|
+
end
|
846
|
+
else
|
847
|
+
results.print(settings.queryFout, settings.opt)
|
848
|
+
settings.queryFout.flush
|
849
|
+
end
|
850
|
+
results.clear
|
851
|
+
|
852
|
+
when PGresult::EMPTY_QUERY
|
853
|
+
success = TRUE
|
854
|
+
|
855
|
+
when PGresult::COMMAND_OK
|
856
|
+
success = TRUE
|
857
|
+
if !settings.quiet
|
858
|
+
printf("%s\n", results.cmdstatus)
|
859
|
+
end
|
860
|
+
|
861
|
+
when PGresult::COPY_OUT
|
862
|
+
success = TRUE
|
863
|
+
if copy_out
|
864
|
+
handleCopyOut(settings, copystream)
|
865
|
+
else
|
866
|
+
if !settings.quiet
|
867
|
+
printf("Copy command returns...\n")
|
868
|
+
end
|
869
|
+
|
870
|
+
handleCopyOut(settings, STDOUT)
|
871
|
+
end
|
872
|
+
|
873
|
+
when PGresult::COPY_IN
|
874
|
+
success = TRUE
|
875
|
+
if copy_in
|
876
|
+
handleCopyIn(settings, FALSE, copystream)
|
877
|
+
else
|
878
|
+
handleCopyIn(settings, !settings.quiet, STDIN)
|
879
|
+
end
|
880
|
+
end
|
881
|
+
|
882
|
+
if (settings.db.status == PGconn::CONNECTION_BAD)
|
883
|
+
printf(STDERR, "We have lost the connection to the backend, so ")
|
884
|
+
printf(STDERR, "further processing is impossible. ")
|
885
|
+
printf(STDERR, "Terminating.\n")
|
886
|
+
exit(2)
|
887
|
+
end
|
888
|
+
|
889
|
+
# check for asynchronous returns
|
890
|
+
# notify = settings.db.notifies()
|
891
|
+
# if notify
|
892
|
+
# printf(STDERR,"ASYNC NOTIFY of '%s' from backend pid '%d' received\n",
|
893
|
+
# notify.relname, notify.be_pid)
|
894
|
+
# end
|
895
|
+
|
896
|
+
rescue
|
897
|
+
printf(STDERR, "%s", $!)
|
898
|
+
success = FALSE
|
899
|
+
end
|
900
|
+
|
901
|
+
return success
|
902
|
+
end
|
903
|
+
|
904
|
+
def MainLoop(settings, source)
|
905
|
+
|
906
|
+
success = TRUE
|
907
|
+
interactive = TRUE
|
908
|
+
insideQuote = FALSE
|
909
|
+
querySent = FALSE
|
910
|
+
done = FALSE
|
911
|
+
|
912
|
+
query = nil
|
913
|
+
queryWaiting = nil
|
914
|
+
slashCmdStatus = -1
|
915
|
+
interactive = (source == STDIN && !settings.notty)
|
916
|
+
|
917
|
+
if settings.quiet
|
918
|
+
settings.prompt = nil
|
919
|
+
else
|
920
|
+
settings.prompt = settings.db.db + PROMPT
|
921
|
+
end
|
922
|
+
|
923
|
+
while !done
|
924
|
+
if slashCmdStatus == 3
|
925
|
+
line = query
|
926
|
+
query = nil
|
927
|
+
else
|
928
|
+
if interactive && !settings.quiet
|
929
|
+
if insideQuote
|
930
|
+
settings.prompt[settings.prompt.length-3,1] = "\'"
|
931
|
+
elsif (queryWaiting != nil && !querySent)
|
932
|
+
settings.prompt[settings.prompt.length-3,1] = "-"
|
933
|
+
else
|
934
|
+
settings.prompt[settings.prompt.length-3,1] = "="
|
935
|
+
end
|
936
|
+
end
|
937
|
+
line = gets(settings.prompt, source)
|
938
|
+
end
|
939
|
+
|
940
|
+
if line == nil
|
941
|
+
printf("EOF\n")
|
942
|
+
done = TRUE
|
943
|
+
else
|
944
|
+
|
945
|
+
### debbegging information ###
|
946
|
+
if !interactive && !settings.singleStep && !settings.quiet
|
947
|
+
printf(STDERR, "%s\n", line)
|
948
|
+
end
|
949
|
+
|
950
|
+
### ommit comment ###
|
951
|
+
begin_comment = line.index("--")
|
952
|
+
if begin_comment
|
953
|
+
line = line[0, begin_comment]
|
954
|
+
end
|
955
|
+
|
956
|
+
### erase unnecessary characters ###
|
957
|
+
line.gsub!(/[ \t\f\n\r]+\z/, "")
|
958
|
+
if line.length == 0
|
959
|
+
next
|
960
|
+
end
|
961
|
+
### begin slash command handling ###
|
962
|
+
if line[0, 1] == "\\"
|
963
|
+
query = line
|
964
|
+
slashCmdStatus, query = HandleSlashCmds(settings, line, nil)
|
965
|
+
if slashCmdStatus == 0 && query != nil
|
966
|
+
success = SendQuery(settings, query, FALSE, FALSE, 0) && success
|
967
|
+
querySent = TRUE
|
968
|
+
elsif slashCmdStatus == 1
|
969
|
+
query = nil
|
970
|
+
elsif slashCmdStatus == 2
|
971
|
+
break
|
972
|
+
end
|
973
|
+
line = nil
|
974
|
+
next
|
975
|
+
end
|
976
|
+
|
977
|
+
### begin query command handling ###
|
978
|
+
slashCmdStatus = -1
|
979
|
+
if settings.singleLineMode
|
980
|
+
success = SendQuery(settings, line, FALSE, FALSE, 0) && success
|
981
|
+
querySent = TRUE
|
982
|
+
else
|
983
|
+
|
984
|
+
if queryWaiting
|
985
|
+
queryWaiting += " " + line
|
986
|
+
else
|
987
|
+
queryWaiting = line
|
988
|
+
end
|
989
|
+
|
990
|
+
for i in 0..line.length-1
|
991
|
+
if line[i, 1] == "\'"
|
992
|
+
insideQuote = !insideQuote
|
993
|
+
end
|
994
|
+
end
|
995
|
+
|
996
|
+
if !insideQuote
|
997
|
+
if line[line.length-1, 1] == ";"
|
998
|
+
query = queryWaiting
|
999
|
+
queryWaiting = nil
|
1000
|
+
|
1001
|
+
success = SendQuery(settings, query, FALSE, FALSE, 0) && success
|
1002
|
+
querySent = TRUE
|
1003
|
+
else
|
1004
|
+
querySent = FALSE
|
1005
|
+
end
|
1006
|
+
else
|
1007
|
+
querySent = FALSE
|
1008
|
+
end
|
1009
|
+
end
|
1010
|
+
end
|
1011
|
+
end # while
|
1012
|
+
return success
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
def main
|
1016
|
+
dbname = nil
|
1017
|
+
host = "localhost"
|
1018
|
+
port = 5432
|
1019
|
+
qfilename = nil
|
1020
|
+
|
1021
|
+
singleQuery = nil
|
1022
|
+
settings = PsqlSettings.new(nil, nil, nil, nil, nil, FALSE, FALSE,
|
1023
|
+
FALSE, FALSE, FALSE, FALSE, FALSE)
|
1024
|
+
settings.opt = PrintOpt.new(FALSE, FALSE, FALSE, FALSE, FALSE,
|
1025
|
+
FALSE, nil, nil, nil, nil)
|
1026
|
+
|
1027
|
+
listDatabases = FALSE
|
1028
|
+
successResult = TRUE
|
1029
|
+
singleSlashCmd = FALSE
|
1030
|
+
|
1031
|
+
settings.opt.align = TRUE
|
1032
|
+
settings.opt.header = TRUE
|
1033
|
+
settings.queryFout = STDOUT
|
1034
|
+
settings.opt.fieldSep = DEFAULT_FIELD_SEP.dup
|
1035
|
+
settings.opt.pager = TRUE
|
1036
|
+
settings.quiet = FALSE
|
1037
|
+
settings.notty = FALSE
|
1038
|
+
settings.useReadline = TRUE
|
1039
|
+
|
1040
|
+
parsed = parseArgs(0, nil, "AelHnsqStx", "a:", "c:", "d:", "f:", "F:",
|
1041
|
+
"h:", "o:", "p:", "T:")
|
1042
|
+
|
1043
|
+
if $OPT_A
|
1044
|
+
settings.opt.align = FALSE
|
1045
|
+
end
|
1046
|
+
|
1047
|
+
if $OPT_a
|
1048
|
+
#fe_setauthsvc(optarg, errbuf);
|
1049
|
+
printf("not implemented, sorry.\n")
|
1050
|
+
exit(1)
|
1051
|
+
end
|
1052
|
+
|
1053
|
+
if $OPT_c
|
1054
|
+
singleQuery = $OPT_c
|
1055
|
+
if singleQuery[0, 1] == "\\"
|
1056
|
+
singleSlashCmd = TRUE
|
1057
|
+
end
|
1058
|
+
end
|
1059
|
+
|
1060
|
+
if $OPT_d
|
1061
|
+
dbname = $OPT_d
|
1062
|
+
end
|
1063
|
+
|
1064
|
+
if $OPT_e
|
1065
|
+
settings.echoQuery = TRUE
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
if $OPT_f
|
1069
|
+
qfilename = $OPT_f
|
1070
|
+
end
|
1071
|
+
|
1072
|
+
if $OPT_F
|
1073
|
+
settings.opt.fieldSep = $OPT_F
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
if $OPT_l
|
1077
|
+
listDatabases = TRUE
|
1078
|
+
end
|
1079
|
+
|
1080
|
+
if $OPT_h
|
1081
|
+
host = $OPT_h
|
1082
|
+
end
|
1083
|
+
|
1084
|
+
if $OPT_H
|
1085
|
+
settings.opt.html3 = TRUE
|
1086
|
+
end
|
1087
|
+
|
1088
|
+
if $OPT_n
|
1089
|
+
settings.useReadline = FALSE
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
if $OPT_o
|
1093
|
+
setFout(settings, $OPT_o)
|
1094
|
+
end
|
1095
|
+
|
1096
|
+
if $OPT_p
|
1097
|
+
port = $OPT_p.to_i
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
if $OPT_q
|
1101
|
+
settings.quiet = TRUE
|
1102
|
+
end
|
1103
|
+
|
1104
|
+
if $OPT_s
|
1105
|
+
settings.singleStep = TRUE
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
if $OPT_S
|
1109
|
+
settings.singleLineMode = TRUE
|
1110
|
+
end
|
1111
|
+
|
1112
|
+
if $OPT_t
|
1113
|
+
settings.opt.header = FALSE
|
1114
|
+
end
|
1115
|
+
|
1116
|
+
if $OPT_T
|
1117
|
+
settings.opt.tableOpt = $OPT_T
|
1118
|
+
end
|
1119
|
+
|
1120
|
+
if $OPT_x
|
1121
|
+
settings.opt.expanded = TRUE
|
1122
|
+
end
|
1123
|
+
|
1124
|
+
if ARGV.length == 1
|
1125
|
+
dbname = ARGV[0]
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
if listDatabases
|
1129
|
+
dbname = "template1"
|
1130
|
+
end
|
1131
|
+
|
1132
|
+
settings.db = PGconn.connect(host, port, "", "", dbname);
|
1133
|
+
dbname = settings.db.db
|
1134
|
+
|
1135
|
+
if settings.db.status() == PGconn::CONNECTION_BAD
|
1136
|
+
printf(STDERR, "Connection to database '%s' failed.\n", dbname)
|
1137
|
+
printf(STDERR, "%s", settings.db.error)
|
1138
|
+
exit(1)
|
1139
|
+
end
|
1140
|
+
if listDatabases
|
1141
|
+
exit(listAllDbs(settings))
|
1142
|
+
end
|
1143
|
+
if (!settings.quiet && !singleQuery && !qfilename)
|
1144
|
+
printf("Welcome to the POSTGRESQL interactive sql monitor:\n")
|
1145
|
+
printf(" Please read the file COPYRIGHT for copyright terms of POSTGRESQL\n\n")
|
1146
|
+
printf(" type \\? for help on slash commands\n")
|
1147
|
+
printf(" type \\q to quit\n")
|
1148
|
+
printf(" type \\g or terminate with semicolon to execute query\n")
|
1149
|
+
printf(" You are currently connected to the database: %s\n\n", dbname)
|
1150
|
+
end
|
1151
|
+
if (qfilename || singleSlashCmd)
|
1152
|
+
if singleSlashCmd
|
1153
|
+
line = singleQuery
|
1154
|
+
else
|
1155
|
+
line = sprintf("\\i %s", qfilename)
|
1156
|
+
end
|
1157
|
+
HandleSlashCmds(settings, line, "")
|
1158
|
+
else
|
1159
|
+
if settings.useReadline
|
1160
|
+
begin
|
1161
|
+
require "readline"
|
1162
|
+
$readline_ok = TRUE
|
1163
|
+
rescue
|
1164
|
+
$readline_ok = FALSE
|
1165
|
+
end
|
1166
|
+
else
|
1167
|
+
$readline_ok = FALSE
|
1168
|
+
end
|
1169
|
+
if singleQuery
|
1170
|
+
success = SendQuery(settings, singleQuery, false, false, 0)
|
1171
|
+
successResult = success
|
1172
|
+
else
|
1173
|
+
successResult = MainLoop(settings, STDIN)
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
settings.db.finish()
|
1177
|
+
return !successResult
|
1178
|
+
end
|
1179
|
+
|
1180
|
+
main
|
1181
|
+
|