2
* Copyright 2006 StartNet s.r.o.
4
* Distributed under MIT license
1
6
package cz.startnet.utils.pgdiff.parsers;
8
import cz.startnet.utils.pgdiff.Resources;
3
9
import cz.startnet.utils.pgdiff.schema.PgColumn;
4
10
import cz.startnet.utils.pgdiff.schema.PgConstraint;
5
11
import cz.startnet.utils.pgdiff.schema.PgDatabase;
6
12
import cz.startnet.utils.pgdiff.schema.PgSchema;
7
13
import cz.startnet.utils.pgdiff.schema.PgTable;
9
import java.util.regex.Matcher;
10
import java.util.regex.Pattern;
14
import java.text.MessageFormat;
13
* Parses CREATE TABLE commands.
17
* Parses CREATE TABLE statements.
17
21
public class CreateTableParser {
20
* Pattern for getting table name from CREATE TABLE.
22
private static final Pattern PATTERN_TABLE_NAME = Pattern.compile(
23
"CREATE[\\s]+TABLE[\\s]+\"?([^\\s\"]+)\"?[\\s]*\\(",
24
Pattern.CASE_INSENSITIVE);
26
* Pattern for getting CONSTRAINT parameters.
28
private static final Pattern PATTERN_CONSTRAINT = Pattern.compile(
29
"CONSTRAINT[\\s]+\"?([^\\s\"]+)\"?[\\s]+(.*)",
30
Pattern.CASE_INSENSITIVE);
32
* Pattern for parsing column definition.
34
private static final Pattern PATTERN_COLUMN = Pattern.compile(
35
"\"?([^\\s\"]+)\"?[\\s]+(.*)", Pattern.CASE_INSENSITIVE);
37
* Pattern for parsing INHERITS.
39
private static final Pattern PATTERN_INHERITS = Pattern.compile(
40
"INHERITS[\\s]+([^;]+)[;]?", Pattern.CASE_INSENSITIVE);
42
* Pattern for checking whether string contains WITH OIDS string.
44
private static final Pattern PATTERN_WITH_OIDS =
45
Pattern.compile(".*WITH[\\s]+OIDS.*", Pattern.CASE_INSENSITIVE);
47
* Pattern for checking whether string contains WITHOUT OIDS
50
private static final Pattern PATTERN_WITHOUT_OIDS =
51
Pattern.compile(".*WITHOUT[\\s]+OIDS.*", Pattern.CASE_INSENSITIVE);
54
24
* Creates a new instance of CreateTableParser.
56
26
private CreateTableParser() {
61
* Parses CREATE TABLE command.
30
* Parses CREATE TABLE statement.
63
32
* @param database database
64
* @param command CREATE TABLE command
66
* @throws ParserException Thrown if problem occured while parsing DDL.
67
* @throws RuntimeException DOCUMENT ME!
33
* @param statement CREATE TABLE statement
69
public static void parse(final PgDatabase database, final String command) {
70
String line = command;
71
final Matcher matcher = PATTERN_TABLE_NAME.matcher(line);
72
final String tableName;
75
tableName = matcher.group(1).trim();
76
line = ParserUtils.removeSubString(
77
line, matcher.start(), matcher.end());
79
throw new ParserException(
80
ParserException.CANNOT_PARSE_COMMAND + line);
35
public static void parse(final PgDatabase database,
36
final String statement) {
37
final Parser parser = new Parser(statement);
38
parser.expect("CREATE", "TABLE");
40
final String tableName = parser.parseIdentifier();
83
41
final PgTable table = new PgTable(ParserUtils.getObjectName(tableName));
84
42
final String schemaName =
85
43
ParserUtils.getSchemaName(tableName, database);
86
44
final PgSchema schema = database.getSchema(schemaName);
88
46
if (schema == null) {
89
throw new RuntimeException(
90
"Cannot get schema '" + schemaName
91
+ "'. Need to issue 'CREATE SCHEMA " + schemaName
92
+ ";' before 'CREATE TABLE " + tableName + "...;'?");
47
throw new RuntimeException(MessageFormat.format(
48
Resources.getString("CannotFindSchemaCreateTable"),
49
schemaName, tableName));
95
52
schema.addTable(table);
96
parseRows(table, ParserUtils.removeLastSemicolon(line));
100
* Parses COLUMN and other DDL within '(' and ')' in CREATE TABLE
103
* @param table table being parsed
104
* @param line line being processed
106
* @throws ParserException Thrown if problem occured while parsing DDL.
108
private static void parseColumnDefs(final PgTable table,
110
if (line.length() > 0) {
111
boolean matched = false;
112
Matcher matcher = PATTERN_CONSTRAINT.matcher(line.trim());
114
if (matcher.matches()) {
115
final PgConstraint constraint =
116
new PgConstraint(matcher.group(1).trim());
117
table.addConstraint(constraint);
118
constraint.setDefinition(matcher.group(2).trim());
119
constraint.setTableName(table.getName());
124
matcher = PATTERN_COLUMN.matcher(line);
126
if (matcher.matches()) {
127
final PgColumn column =
128
new PgColumn(matcher.group(1).trim());
129
table.addColumn(column);
130
column.parseDefinition(matcher.group(2).trim());
136
throw new ParserException(
137
ParserException.CANNOT_PARSE_COMMAND + line);
143
* Parses definitions that are present after column definition is
146
* @param table table being parsed
147
* @param commands commands being processed
149
* @return true if the command was the last command for CREATE TABLE,
152
private static String parsePostColumns(final PgTable table,
153
final String commands) {
154
String line = commands;
155
final Matcher matcher = PATTERN_INHERITS.matcher(line);
157
if (matcher.find()) {
158
table.setInherits(matcher.group(1).trim());
159
line = ParserUtils.removeSubString(
160
line, matcher.start(), matcher.end());
163
if (PATTERN_WITH_OIDS.matcher(line).matches()) {
164
table.setWithOIDS(true);
165
line = ParserUtils.removeSubString(line, "WITH OIDS");
166
} else if (PATTERN_WITHOUT_OIDS.matcher(line).matches()) {
167
table.setWithOIDS(false);
168
line = ParserUtils.removeSubString(line, "WITHOUT OIDS");
175
* Parses all rows in CREATE TABLE command.
177
* @param table table being parsed
178
* @param command command without 'CREATE SEQUENCE ... (' string
180
* @throws ParserException Thrown if problem occured with parsing of DDL.
182
private static void parseRows(final PgTable table, final String command) {
183
String line = command;
184
boolean postColumns = false;
187
while (line.length() > 0) {
188
final int commandEnd = ParserUtils.getCommandEnd(line, 0);
189
final String subCommand = line.substring(0, commandEnd).trim();
192
line = parsePostColumns(table, subCommand);
195
} else if (line.charAt(commandEnd) == ')') {
199
parseColumnDefs(table, subCommand);
200
line = (commandEnd >= line.length()) ? ""
201
: line.substring(commandEnd + 1);
203
} catch (RuntimeException ex) {
204
throw new ParserException(
205
ParserException.CANNOT_PARSE_COMMAND + "CREATE TABLE "
206
+ table.getName() + " ( " + command, ex);
211
if (line.length() > 0) {
212
throw new ParserException(
213
"Cannot parse CREATE TABLE '" + table.getName()
214
+ "' - do not know how to parse '" + line + "'");
56
while (!parser.expectOptional(")")) {
57
if (parser.expectOptional("CONSTRAINT")) {
58
parseConstraint(parser, table);
60
parseColumn(parser, table);
63
if (parser.expectOptional(")")) {
70
while (!parser.expectOptional(";")) {
71
if (parser.expectOptional("INHERITS")) {
72
parseInherits(parser, table);
73
} else if (parser.expectOptional("WITHOUT")) {
74
table.setWith("OIDS=false");
75
} else if (parser.expectOptional("WITH")) {
76
if (parser.expectOptional("OIDS")
77
|| parser.expectOptional("OIDS=true")) {
78
table.setWith("OIDS=true");
79
} else if (parser.expectOptional("OIDS=false")) {
80
table.setWith("OIDS=false");
82
table.setWith(parser.getExpression());
84
} else if (parser.expectOptional("TABLESPACE")) {
85
table.setTablespace(parser.parseString());
87
parser.throwUnsupportedCommand();
95
* @param parser parser
96
* @param table pg table
98
private static void parseInherits(final Parser parser,
99
final PgTable table) {
102
while (!parser.expectOptional(")")) {
104
ParserUtils.getObjectName(parser.parseIdentifier()));
106
if (parser.expectOptional(")")) {
115
* Parses CONSTRAINT definition.
117
* @param parser parser
118
* @param table pg table
120
private static void parseConstraint(final Parser parser,
121
final PgTable table) {
122
final PgConstraint constraint = new PgConstraint(
123
ParserUtils.getObjectName(parser.parseIdentifier()));
124
table.addConstraint(constraint);
125
constraint.setDefinition(parser.getExpression());
126
constraint.setTableName(table.getName());
130
* Parses column definition.
132
* @param parser parser
133
* @param table pg table
135
private static void parseColumn(final Parser parser, final PgTable table) {
136
final PgColumn column = new PgColumn(
137
ParserUtils.getObjectName(parser.parseIdentifier()));
138
table.addColumn(column);
139
column.parseDefinition(parser.getExpression());