| 276 | } |
| 277 | |
| 278 | string PrintPath(const TableDescriptor& tbl_desc, const SchemaPath& path) { |
| 279 | stringstream ss; |
| 280 | ss << tbl_desc.database() << "." << tbl_desc.name(); |
| 281 | const ColumnType* type = nullptr; |
| 282 | if (path.size() > 0) { |
| 283 | ss << "." << tbl_desc.col_descs()[path[0]].name(); |
| 284 | type = &tbl_desc.col_descs()[path[0]].type(); |
| 285 | } |
| 286 | for (int i = 1; i < path.size(); ++i) { |
| 287 | ss << "."; |
| 288 | switch (type->type) { |
| 289 | case TYPE_ARRAY: |
| 290 | if (path[i] == 0) { |
| 291 | ss << "item"; |
| 292 | type = &type->children[0]; |
| 293 | } else { |
| 294 | DCHECK_EQ(path[i], 1); |
| 295 | ss << "pos"; |
| 296 | type = nullptr; |
| 297 | } |
| 298 | break; |
| 299 | case TYPE_MAP: |
| 300 | if (path[i] == 0) { |
| 301 | ss << "key"; |
| 302 | type = &type->children[0]; |
| 303 | } else if (path[i] == 1) { |
| 304 | ss << "value"; |
| 305 | type = &type->children[1]; |
| 306 | } else { |
| 307 | DCHECK_EQ(path[i], 2); |
| 308 | ss << "pos"; |
| 309 | type = nullptr; |
| 310 | } |
| 311 | break; |
| 312 | case TYPE_STRUCT: |
| 313 | DCHECK_LT(path[i], type->children.size()); |
| 314 | ss << type->field_names[path[i]]; |
| 315 | type = &type->children[path[i]]; |
| 316 | break; |
| 317 | default: |
| 318 | DCHECK_EQ(path.size() - 1, i) << PrintNumericPath(path) << " " |
| 319 | << i <<" " << type->DebugString(); |
| 320 | ss << "(" << type->DebugString() << ")"; |
| 321 | } |
| 322 | } |
| 323 | return ss.str(); |
| 324 | } |
| 325 | |
| 326 | string PrintSubPath(const TableDescriptor& tbl_desc, const SchemaPath& path, |
| 327 | int end_path_idx) { |
no test coverage detected