1 """
2 Exceptions and helper functions for ADQL processing.
3 """
4
5
6
7
8
9
10
11 from gavo import utils
12
14 """A base class for the exceptions from this module.
15 """
16
17 pass
18
20 """is raised for features we don't (yet) support.
21 """
22
24 """is raised if a column name cannot be resolved.
25 """
29
31 """is raised when a table name cannot be resolved.
32 """
33 - def __init__(self, tableName, hint=None):
36
38 """is raised when the expectations of the to-ADQL morphers are violated.
39 """
40 pass
41
43 """is raised if a column name matches more than one column in a
44 compound query.
45 """
46
48 """is raised if a node is asked for a non-existing child.
49 """
51 self.searchedType, self.toks = searchedType, toks
52
54 return "No %s child found in %s"%(self.searchedType, self.toks)
55
57 """is raised if a node is asked for a unique child but has more than
58 one.
59 """
61 return "Multiple %s children found in %s"%(self.searchedType,
62 self.toks)
63
65 """is raised when an ADQL node is constructed with bad keywords.
66
67 This is a development help and should not occur in production code.
68 """
71
72
74 """is raised if something is wrong with a call to a user defined
75 function.
76 """
77
79 """is raised if something is wrong with a geometry.
80 """
81
83 """is raised if a region specification is in some way bad.
84 """
85
87 """is raised when something cannot be flattened.
88 """
89
91 """is raised when the operands of a set operation are not deemed
92 compatible.
93 """
94
96 """is a sentinel to pass as default to nodes.getChildOfType.
97 """
98
99
101 """returns the only item of matches if there is exactly one, raises an
102 appropriate exception if not.
103 """
104 if len(matches)==1:
105 return matches[0]
106 elif not matches:
107 raise ColumnNotFound(colName)
108 else:
109 matches = set(matches)
110 if len(matches)!=1:
111 raise AmbiguousColumn(colName)
112 else:
113 return matches.pop()
114
115
117 """returns a set of column names that only occur once in the result
118 table.
119
120 For a natural join, that's all column names occurring in all tables,
121 for a USING join, that's all names occurring in USING, else it's
122 an empty set.
123
124 """
125 joinType = getattr(tableNode, "getJoinType", lambda: "CROSS")()
126 if joinType=="NATURAL":
127
128 return reduce(lambda a,b: a&b,
129 [set(t.fieldInfos.columns) for t in tableNode.joinedTables])
130 elif joinType=="USING":
131 return set(tableNode.joinSpecification.usingColumns)
132 else:
133 return set()
134
135
137 """An abstract method to retrieve table metadata.
138
139 A subclass of this must be passed into adql.parseAnnotating.
140 Implementations must fill out the getInfosFor(tableName) method,
141 which must return a sequence of (column name, adql.FieldInfo) pairs
142 for the named table.
143
144 plain strings for table names will be normalised (lowercased).
145 """
147 self.extraFieldInfos = {}
148 self.cache = {}
149
158
170
172 """adds field infos for tableName.
173
174 fieldInfos must be a sequence of (columnName, adql.FieldInfo) pairs.
175
176 Note that tableName is normalised to lowercase here.
177 """
178 self.extraFieldInfos[self.normalizeName(tableName)] = fieldInfos
179
182