001: /*
002: * Copyright 2004-2008 H2 Group. Licensed under the H2 License, Version 1.0
003: * (http://h2database.com/html/license.html).
004: * Initial Developer: H2 Group
005: */
006: package org.h2.server.pg;
007:
008: import java.io.IOException;
009: import java.net.ServerSocket;
010: import java.net.Socket;
011: import java.sql.Connection;
012: import java.sql.PreparedStatement;
013: import java.sql.ResultSet;
014: import java.sql.SQLException;
015: import java.sql.Timestamp;
016: import java.util.ArrayList;
017: import java.util.Collections;
018: import java.util.HashSet;
019: import java.util.Set;
020:
021: import org.h2.engine.Constants;
022: import org.h2.server.Service;
023: import org.h2.util.MathUtils;
024: import org.h2.util.NetUtils;
025:
026: /**
027: * This class implements a subset of the PostgreSQL protocol as described here:
028: * http://developer.postgresql.org/pgdocs/postgres/protocol.html
029: * The PostgreSQL catalog is described here:
030: * http://www.postgresql.org/docs/7.4/static/catalogs.html
031: */
032: public class PgServer implements Service {
033:
034: public static final int DEFAULT_PORT = 5435; // also in the docs
035:
036: private int port = PgServer.DEFAULT_PORT;
037: private boolean stop;
038: private boolean log;
039: private ServerSocket serverSocket;
040: private Set running = Collections.synchronizedSet(new HashSet());
041: private String baseDir;
042: private String url;
043: private boolean allowOthers;
044: private boolean ifExists;
045:
046: public void init(String[] args) throws Exception {
047: port = DEFAULT_PORT;
048: for (int i = 0; i < args.length; i++) {
049: String a = args[i];
050: if ("-log".equals(a)) {
051: log = Boolean.valueOf(args[++i]).booleanValue();
052: } else if ("-pgPort".equals(a)) {
053: port = MathUtils.decodeInt(args[++i]);
054: } else if ("-baseDir".equals(a)) {
055: baseDir = args[++i];
056: } else if ("-pgAllowOthers".equals(a)) {
057: allowOthers = Boolean.valueOf(args[++i]).booleanValue();
058: } else if ("-ifExists".equals(a)) {
059: ifExists = Boolean.valueOf(args[++i]).booleanValue();
060: }
061: }
062: org.h2.Driver.load();
063: url = "pg://" + NetUtils.getLocalAddress() + ":" + port;
064:
065: // int testing;
066: // log = true;
067: }
068:
069: boolean getLog() {
070: return log;
071: }
072:
073: void log(String s) {
074: if (log) {
075: System.out.println(s);
076: }
077: }
078:
079: synchronized void remove(PgServerThread t) {
080: running.remove(t);
081: }
082:
083: void logError(Exception e) {
084: if (log) {
085: e.printStackTrace();
086: }
087: }
088:
089: public String getURL() {
090: return url;
091: }
092:
093: boolean allow(Socket socket) {
094: if (allowOthers) {
095: return true;
096: }
097: return NetUtils.isLoopbackAddress(socket);
098: }
099:
100: public void start() throws SQLException {
101: serverSocket = NetUtils.createServerSocket(port, false);
102: }
103:
104: public void listen() {
105: String threadName = Thread.currentThread().getName();
106: try {
107: while (!stop) {
108: Socket s = serverSocket.accept();
109: if (!allow(s)) {
110: log("Connection not allowed");
111: s.close();
112: } else {
113: PgServerThread c = new PgServerThread(s, this );
114: running.add(c);
115: c.setProcessId(running.size());
116: Thread thread = new Thread(c);
117: thread.setName(threadName + " thread");
118: c.setThread(thread);
119: thread.start();
120: }
121: }
122: } catch (Exception e) {
123: if (!stop) {
124: e.printStackTrace();
125: }
126: }
127: }
128:
129: public void stop() {
130: // TODO server: combine with tcp server
131: if (!stop) {
132: stop = true;
133: if (serverSocket != null) {
134: try {
135: serverSocket.close();
136: } catch (IOException e) {
137: // TODO log exception
138: e.printStackTrace();
139: }
140: serverSocket = null;
141: }
142: }
143: // TODO server: using a boolean 'now' argument? a timeout?
144: ArrayList list = new ArrayList(running);
145: for (int i = 0; i < list.size(); i++) {
146: PgServerThread c = (PgServerThread) list.get(i);
147: c.close();
148: try {
149: Thread t = c.getThread();
150: if (t != null) {
151: t.join(100);
152: }
153: } catch (Exception e) {
154: // TODO log exception
155: e.printStackTrace();
156: }
157: }
158: }
159:
160: public boolean isRunning() {
161: if (serverSocket == null) {
162: return false;
163: }
164: try {
165: Socket s = NetUtils.createLoopbackSocket(serverSocket
166: .getLocalPort(), false);
167: s.close();
168: return true;
169: } catch (Exception e) {
170: return false;
171: }
172: }
173:
174: public String getBaseDir() {
175: return baseDir;
176: }
177:
178: public boolean getAllowOthers() {
179: return allowOthers;
180: }
181:
182: public String getType() {
183: return "PG";
184: }
185:
186: public String getName() {
187: return "H2 PG Server";
188: }
189:
190: public boolean getIfExists() {
191: return ifExists;
192: }
193:
194: /**
195: * The Java implementation of the PostgreSQL function pg_get_indexdef. The
196: * method is used to get CREATE INDEX command for an index, or the column
197: * definition of one column in the index.
198: *
199: * @param conn the connection
200: * @param indexId the index id
201: * @param ordinalPosition the ordinal position (null if the SQL statement
202: * should be returned)
203: * @param pretty this flag is ignored
204: * @return the SQL statement or the column name
205: */
206: public static String getIndexColumn(Connection conn, int indexId,
207: Integer ordinalPosition, Boolean pretty)
208: throws SQLException {
209: if (ordinalPosition == null || ordinalPosition.intValue() == 0) {
210: PreparedStatement prep = conn
211: .prepareStatement("select sql from information_schema.indexes where id=?");
212: prep.setInt(1, indexId);
213: ResultSet rs = prep.executeQuery();
214: if (rs.next()) {
215: return rs.getString(1);
216: }
217: return null;
218: } else {
219: PreparedStatement prep = conn
220: .prepareStatement("select column_name from information_schema.indexes where id=? and ordinal_position=?");
221: prep.setInt(1, indexId);
222: prep.setInt(2, ordinalPosition.intValue());
223: ResultSet rs = prep.executeQuery();
224: if (rs.next()) {
225: return rs.getString(1);
226: }
227: return null;
228: }
229: }
230:
231: public static String getCurrentSchema(Connection conn)
232: throws SQLException {
233: ResultSet rs = conn.createStatement().executeQuery(
234: "call schema()");
235: rs.next();
236: return rs.getString(1);
237: }
238:
239: public static String getEncodingName(int code) throws SQLException {
240: switch (code) {
241: case 0:
242: return "SQL_ASCII";
243: case 6:
244: return "UTF8";
245: case 8:
246: return "LATIN1";
247: default:
248: return code < 40 ? "UTF8" : "";
249: }
250: }
251:
252: public static String getVersion() {
253: return "PostgreSQL 8.1.4 server protocol using H2 "
254: + Constants.getVersion();
255: }
256:
257: public static Timestamp getStartTime() {
258: return new Timestamp(System.currentTimeMillis());
259: }
260:
261: public static String getUserById(Connection conn, int id)
262: throws SQLException {
263: PreparedStatement prep = conn
264: .prepareStatement("SELECT NAME FROM INFORMATION_SCHEMA.USERS WHERE ID=?");
265: prep.setInt(1, id);
266: ResultSet rs = prep.executeQuery();
267: if (rs.next()) {
268: return rs.getString(1);
269: }
270: return null;
271: }
272:
273: public static boolean hasDatabasePrivilege(int id, String privilege) {
274: return true;
275: }
276:
277: public static boolean hasTablePrivilege(String table,
278: String privilege) {
279: return true;
280: }
281:
282: public static int getCurrentTid(String table, String id) {
283: return 1;
284: }
285:
286: }
|