/Users/deen/code/yugabyte-db/src/yb/yql/cql/ql/ptree/pt_dml_write_property.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) YugaByte, Inc. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except |
4 | | // in compliance with the License. You may obtain a copy of the License at |
5 | | // |
6 | | // http://www.apache.org/licenses/LICENSE-2.0 |
7 | | // |
8 | | // Unless required by applicable law or agreed to in writing, software distributed under the License |
9 | | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express |
10 | | // or implied. See the License for the specific language governing permissions and limitations |
11 | | // under the License. |
12 | | // |
13 | | #include "yb/yql/cql/ql/ptree/pt_dml_write_property.h" |
14 | | |
15 | | #include <set> |
16 | | |
17 | | #include "yb/client/schema.h" |
18 | | #include "yb/util/string_case.h" |
19 | | #include "yb/yql/cql/ql/ptree/pt_expr.h" |
20 | | #include "yb/yql/cql/ql/ptree/sem_context.h" |
21 | | #include "yb/yql/cql/ql/ptree/yb_location.h" |
22 | | |
23 | | namespace yb { |
24 | | namespace ql { |
25 | | |
26 | | using strings::Substitute; |
27 | | using client::YBColumnSchema; |
28 | | |
29 | | // These property names need to be lowercase, since identifiers are converted to lowercase by the |
30 | | // scanner phase and as a result if we're doing string matching everything should be lowercase. |
31 | | const std::map<std::string, PTDmlWriteProperty::KVProperty> PTDmlWriteProperty::kPropertyDataTypes |
32 | | = { |
33 | | {"options", KVProperty::kOptions} |
34 | | }; |
35 | | |
36 | | PTDmlWriteProperty::PTDmlWriteProperty(MemoryContext *memctx, |
37 | | YBLocation::SharedPtr loc, |
38 | | const MCSharedPtr<MCString>& lhs, |
39 | | const PTExprPtr& rhs) |
40 | | : PTProperty(memctx, loc, lhs, rhs), |
41 | 56 | property_type_(DmlWritePropertyType::kDmlWriteProperty) {} |
42 | | |
43 | | PTDmlWriteProperty::PTDmlWriteProperty(MemoryContext *memctx, |
44 | | YBLocation::SharedPtr loc) |
45 | 56 | : PTProperty(memctx, loc) { |
46 | 56 | } |
47 | | |
48 | 64 | PTDmlWriteProperty::~PTDmlWriteProperty() { |
49 | 64 | } |
50 | | |
51 | 0 | CHECKED_STATUS PTDmlWriteProperty::Analyze(SemContext *sem_context) { |
52 | | |
53 | | // Verify we have a valid property name in the lhs. |
54 | 0 | const auto& update_property_name = lhs_->c_str(); |
55 | 0 | auto iterator = kPropertyDataTypes.find(update_property_name); |
56 | 0 | if (iterator == kPropertyDataTypes.end()) { |
57 | 0 | return sem_context->Error(this, Substitute("Unknown property '$0'", lhs_->c_str()).c_str(), |
58 | 0 | ErrorCode::INVALID_UPDATE_PROPERTY); |
59 | 0 | } |
60 | | |
61 | 0 | if (iterator->second == KVProperty::kOptions) { |
62 | 0 | return sem_context->Error(this, |
63 | 0 | Substitute("Invalid value for property '$0'. Value must be a map", |
64 | 0 | update_property_name).c_str(), |
65 | 0 | ErrorCode::DATATYPE_MISMATCH); |
66 | 0 | } |
67 | | |
68 | 0 | return Status::OK(); |
69 | 0 | } |
70 | | |
71 | 0 | std::ostream& operator<<(ostream& os, const DmlWritePropertyType& property_type) { |
72 | 0 | switch(property_type) { |
73 | 0 | case DmlWritePropertyType::kDmlWriteProperty: |
74 | 0 | os << "kDmlWriteProperty"; |
75 | 0 | break; |
76 | 0 | case DmlWritePropertyType::kDmlWritePropertyMap: |
77 | 0 | os << "kDmlWritePropertyMap"; |
78 | 0 | break; |
79 | 0 | } |
80 | 0 | return os; |
81 | 0 | } |
82 | | |
83 | 0 | void PTDmlWriteProperty::PrintSemanticAnalysisResult(SemContext *sem_context) { |
84 | 0 | VLOG(3) << "SEMANTIC ANALYSIS RESULT (" << *loc_ << "):\n" << "Not yet avail"; |
85 | 0 | } |
86 | | |
87 | 54 | CHECKED_STATUS PTDmlWritePropertyListNode::Analyze(SemContext *sem_context) { |
88 | | // Set to ensure we don't have duplicate update properties. |
89 | 54 | std::set<string> update_properties; |
90 | 54 | std::unordered_map<string, PTDmlWriteProperty::SharedPtr> order_tnodes; |
91 | 54 | vector<string> order_columns; |
92 | 56 | for (PTDmlWriteProperty::SharedPtr tnode : node_list()) { |
93 | 56 | if (tnode == nullptr) { |
94 | | // This shouldn't happen because AppendList ignores null nodes. |
95 | 0 | LOG(ERROR) << "Invalid null property"; |
96 | 0 | continue; |
97 | 0 | } |
98 | 56 | switch(tnode->property_type()) { |
99 | 0 | case DmlWritePropertyType::kDmlWriteProperty: FALLTHROUGH_INTENDED; |
100 | 56 | case DmlWritePropertyType::kDmlWritePropertyMap: { |
101 | 56 | string update_property_name = tnode->lhs()->c_str(); |
102 | 56 | if (update_properties.find(update_property_name) != update_properties.end()) { |
103 | 2 | return sem_context->Error(this, ErrorCode::DUPLICATE_UPDATE_PROPERTY); |
104 | 2 | } |
105 | 54 | RETURN_NOT_OK(tnode->Analyze(sem_context)); |
106 | 52 | update_properties.insert(update_property_name); |
107 | 52 | break; |
108 | 54 | } |
109 | 56 | } |
110 | 56 | } |
111 | | |
112 | 50 | return Status::OK(); |
113 | 54 | } |
114 | | |
115 | 220 | bool PTDmlWritePropertyListNode::ignore_null_jsonb_attributes() { |
116 | 220 | for (PTDmlWriteProperty::SharedPtr tnode : node_list()) { |
117 | 220 | if (tnode->property_type() == DmlWritePropertyType::kDmlWritePropertyMap219 ) { |
118 | 220 | string update_property_name = tnode->lhs()->c_str(); |
119 | 220 | if (update_property_name == "options") { |
120 | 220 | return \ |
121 | 220 | (std::static_pointer_cast<PTDmlWritePropertyMap>(tnode))->ignore_null_jsonb_attributes(); |
122 | 220 | } |
123 | 220 | } |
124 | 219 | } |
125 | 0 | return false; // the default |
126 | 220 | } |
127 | | |
128 | | const std::map<string, PTDmlWritePropertyMap::PropertyMapType> \ |
129 | | PTDmlWritePropertyMap::kPropertyDataTypes |
130 | | = { |
131 | | {"options", PTDmlWritePropertyMap::PropertyMapType::kOptions} |
132 | | }; |
133 | | |
134 | | PTDmlWritePropertyMap::PTDmlWritePropertyMap(MemoryContext *memctx, |
135 | | YBLocation::SharedPtr loc) |
136 | 56 | : PTDmlWriteProperty(memctx, loc) { |
137 | 56 | property_type_ = DmlWritePropertyType::kDmlWritePropertyMap; |
138 | 56 | map_elements_ = TreeListNode<PTDmlWriteProperty>::MakeShared(memctx, loc); |
139 | 56 | } |
140 | | |
141 | 32 | PTDmlWritePropertyMap::~PTDmlWritePropertyMap() { |
142 | 32 | } |
143 | | |
144 | 54 | CHECKED_STATUS PTDmlWritePropertyMap::Analyze(SemContext *sem_context) { |
145 | | // Verify we have a valid property name in the lhs. |
146 | 54 | const auto &property_name = lhs_->c_str(); |
147 | 54 | auto iterator = kPropertyDataTypes.find(property_name); |
148 | 54 | if (iterator == kPropertyDataTypes.end()) { |
149 | 0 | if (IsValidProperty(property_name)) { |
150 | 0 | return sem_context->Error(this, Substitute("Invalid map value for property '$0'", |
151 | 0 | property_name).c_str(), |
152 | 0 | ErrorCode::DATATYPE_MISMATCH); |
153 | 0 | } |
154 | 0 | return sem_context->Error(this, Substitute("Unknown property '$0'", property_name).c_str(), |
155 | 0 | ErrorCode::INVALID_UPDATE_PROPERTY); |
156 | 0 | } |
157 | | |
158 | 54 | const auto &property_type = iterator->second; |
159 | | |
160 | 54 | switch (property_type) { |
161 | 54 | case PropertyMapType::kOptions: |
162 | 54 | RETURN_SEM_CONTEXT_ERROR_NOT_OK(AnalyzeOptions(sem_context)); |
163 | 52 | break; |
164 | 54 | } |
165 | 52 | return Status::OK(); |
166 | 54 | } |
167 | | |
168 | 0 | void PTDmlWritePropertyMap::PrintSemanticAnalysisResult(SemContext *sem_context) { |
169 | 0 | VLOG(3) << "SEMANTIC ANALYSIS RESULT (" << *loc_ << "):\n" << "Not yet avail"; |
170 | 0 | } |
171 | | |
172 | 56 | Status PTDmlWritePropertyMap::AnalyzeOptions(SemContext *sem_context) { |
173 | 56 | for (const auto& subproperty : map_elements_->node_list()) { |
174 | 56 | string subproperty_name; |
175 | 56 | ToLowerCase(subproperty->lhs()->c_str(), &subproperty_name); |
176 | 56 | auto iter = Options::kSubpropertyDataTypes.find(subproperty_name); |
177 | 56 | if (iter == Options::kSubpropertyDataTypes.end()) { |
178 | 4 | return STATUS(InvalidArgument, Substitute("Unknown options property $0", |
179 | 4 | subproperty_name)); |
180 | 4 | } |
181 | | |
182 | 52 | bool bool_val; |
183 | 52 | switch(iter->second) { |
184 | 52 | case Options::Subproperty::kIgnoreNullJsonbAttributes: |
185 | 52 | RETURN_NOT_OK(GetBoolValueFromExpr(subproperty->rhs(), subproperty_name, &bool_val)); |
186 | 52 | break; |
187 | 52 | } |
188 | 52 | } |
189 | 52 | return Status::OK(); |
190 | 56 | } |
191 | | |
192 | 220 | bool PTDmlWritePropertyMap::ignore_null_jsonb_attributes() { |
193 | 220 | for (const auto& subproperty : map_elements_->node_list()) { |
194 | 220 | string subproperty_name; |
195 | 220 | ToLowerCase(subproperty->lhs()->c_str(), &subproperty_name); |
196 | 220 | auto iter = Options::kSubpropertyDataTypes.find(subproperty_name); |
197 | 220 | if (iter != Options::kSubpropertyDataTypes.end() && |
198 | 220 | iter->second == Options::Subproperty::kIgnoreNullJsonbAttributes) { |
199 | 220 | return std::dynamic_pointer_cast<PTConstBool>(subproperty->rhs())->Eval(); |
200 | 220 | } |
201 | 220 | } |
202 | 0 | return false; // Default if the property isn't specified |
203 | 220 | } |
204 | | |
205 | | const std::map<std::string, Options::Subproperty> |
206 | | Options::kSubpropertyDataTypes = { |
207 | | {"ignore_null_jsonb_attributes", Options::Subproperty::kIgnoreNullJsonbAttributes} |
208 | | }; |
209 | | |
210 | | } // namespace ql |
211 | | } // namespace yb |