43 |
43 |
** IAS 20220926 Fixed READ-XMLSCHEMA support.
|
44 |
44 |
** IAS 20221014 More fixes to READ-XMLSCHEMA support.
|
45 |
45 |
** IAS 20221018 Fixed processing of 'now' and 'today' INITIAL attribute value.
|
|
46 |
** IAS 20221116 Fixed READ-XMLSCHEMA support for DATASET..
|
46 |
47 |
*/
|
47 |
48 |
|
48 |
49 |
/*
|
... | ... | |
102 |
103 |
|
103 |
104 |
import java.io.*;
|
104 |
105 |
import java.lang.reflect.*;
|
|
106 |
import java.nio.file.*;
|
105 |
107 |
import java.util.*;
|
106 |
108 |
import java.util.function.*;
|
107 |
109 |
import java.util.logging.*;
|
... | ... | |
177 |
179 |
/** The future name of the read temp-table. */
|
178 |
180 |
private String ttName = null;
|
179 |
181 |
|
|
182 |
/** The future namesapece prefix of the read temp-table. */
|
|
183 |
private String ttPrefix = null;
|
|
184 |
|
180 |
185 |
/** The desired mapping of fields to new type, if one is defined. */
|
181 |
186 |
private final Map<String, String> fieldTypeMapping;
|
182 |
187 |
|
183 |
188 |
/** 'External' schema location, if one is provided. */
|
184 |
189 |
private final String schemaLocation;
|
185 |
190 |
|
|
191 |
/** Flag indicating that we're reading external schema */
|
|
192 |
private boolean external = false;
|
|
193 |
|
186 |
194 |
/**
|
187 |
195 |
* The set of temp-table builders for a dataset. They are mapped by their (XML-) names. They
|
188 |
196 |
* are collected while parsing the schema and since their indexes are available only at the end
|
... | ... | |
1016 |
1024 |
private boolean readDatasetSchema(boolean verify)
|
1017 |
1025 |
throws XMLStreamException
|
1018 |
1026 |
{
|
|
1027 |
Map<String, TempTableBuilder> extenalSchemas = new HashMap<>();
|
1019 |
1028 |
Relation keyrefRel = null;
|
|
1029 |
String nsPrefix = null;
|
1020 |
1030 |
while (reader.hasNext())
|
1021 |
1031 |
{
|
1022 |
1032 |
int type = reader.next();
|
... | ... | |
1052 |
1062 |
if (ds._dynamic())
|
1053 |
1063 |
{
|
1054 |
1064 |
ds.name(datasetName);
|
|
1065 |
nsPrefix = getXmlAttribute("prodata:prefix");
|
|
1066 |
ds.namespacePrefix(nsPrefix);
|
1055 |
1067 |
}
|
1056 |
1068 |
// else simply ignore it (?)
|
1057 |
1069 |
}
|
1058 |
1070 |
else
|
1059 |
1071 |
{
|
1060 |
1072 |
String tableName = getXmlAttribute("prodata:tableName");
|
|
1073 |
TempTableBuilder ttb = null;
|
|
1074 |
String tableRef = null;
|
1061 |
1075 |
if (tableName == null)
|
1062 |
1076 |
{
|
1063 |
1077 |
// if dedicated attribute not found, use the xml name attribute
|
1064 |
1078 |
tableName = getXmlAttribute("name");
|
1065 |
1079 |
}
|
|
1080 |
if (tableName == null)
|
|
1081 |
{
|
|
1082 |
tableRef = getXmlAttribute("ref");
|
|
1083 |
ttb = extenalSchemas.get(tableRef);
|
|
1084 |
if (ttb == null)
|
|
1085 |
{
|
|
1086 |
throw new IllegalStateException("Unknown table reference: ["
|
|
1087 |
+ tableRef + "]");
|
|
1088 |
}
|
|
1089 |
tableName = removeNsPrefix(tableRef);
|
|
1090 |
}
|
1066 |
1091 |
handle buffer = ds.bufferHandle(tableName);
|
1067 |
1092 |
if (verifySchemaMode == Verify.STRICT && verify && !buffer._isValid())
|
1068 |
1093 |
{
|
... | ... | |
1074 |
1099 |
// Temp-table '<table>' not found in XML Schema
|
1075 |
1100 |
return false;
|
1076 |
1101 |
}
|
1077 |
|
if (!readTableSchema(tableName, null))
|
|
1102 |
if (ttb != null)
|
|
1103 |
{
|
|
1104 |
tables.put(tableName, ttb);
|
|
1105 |
String xmlNodeName = ttb.getXmlNodeName().getValue();
|
|
1106 |
tablesByXmlName.put(
|
|
1107 |
new CaseInsensitiveString(xmlNodeName == null ? tableName :
|
|
1108 |
xmlNodeName),
|
|
1109 |
tableName);
|
|
1110 |
|
|
1111 |
}
|
|
1112 |
else
|
|
1113 |
{
|
|
1114 |
if (!readTableSchema(tableName, null))
|
|
1115 |
{
|
|
1116 |
return false;
|
|
1117 |
}
|
|
1118 |
}
|
|
1119 |
}
|
|
1120 |
break;
|
|
1121 |
|
|
1122 |
case "import":
|
|
1123 |
if (ds != null)
|
|
1124 |
{
|
|
1125 |
String schemaLocation = getXmlAttribute("schemaLocation");
|
|
1126 |
String extPath = !Serializator.TYPE_FILE.equals(
|
|
1127 |
source.getType().toUpperCase()) ? null :
|
|
1128 |
Paths.get(source.getFileName()).getParent().toString() +
|
|
1129 |
"/" + schemaLocation;
|
|
1130 |
if (extPath == null)
|
|
1131 |
{
|
|
1132 |
ErrorManager.recordOrThrowError(
|
|
1133 |
new int[] {293, 13101, 13032},
|
|
1134 |
new String[] {
|
|
1135 |
"** \"" + schemaLocation + "\" was not found",
|
|
1136 |
"Unable to load imported or included schema: " + schemaLocation,
|
|
1137 |
"Unable to create Temp-Table or dataset schema from XML Schema"
|
|
1138 |
},
|
|
1139 |
false, false, true);
|
|
1140 |
}
|
|
1141 |
String ns = getXmlAttribute("namespace");
|
|
1142 |
XmlImport ext = new XmlImport(new SourceData("file", extPath),
|
|
1143 |
null, schemaLocation, false, null, null);
|
|
1144 |
ext.external = true;
|
|
1145 |
TempTableBuilder ttb = new TempTableBuilder();
|
|
1146 |
if (!ext.importTempTableSchema(ttb))
|
1078 |
1147 |
{
|
1079 |
1148 |
return false;
|
1080 |
1149 |
}
|
|
1150 |
String tableName = ext.ttName;
|
|
1151 |
String tableRef = (ext.ttPrefix == null ? "" :
|
|
1152 |
ext.ttPrefix + ":") + tableName;
|
|
1153 |
extenalSchemas.put(tableRef, ttb);
|
1081 |
1154 |
}
|
1082 |
1155 |
break;
|
1083 |
1156 |
|
1084 |
1157 |
case ELEM_SCHEMA:
|
1085 |
1158 |
// check "xmlns:xsd", "xmlns", and "xmlns:prodata" attributes
|
|
1159 |
ds.namespaceURI(getXmlAttribute("targetNamespace"));
|
1086 |
1160 |
break;
|
1087 |
1161 |
|
1088 |
1162 |
case "unique":
|
... | ... | |
1090 |
1164 |
indexName = getXmlAttribute("prodata:indexName");
|
1091 |
1165 |
primary = Boolean.parseBoolean(getXmlAttribute("prodata:primaryIndex"));
|
1092 |
1166 |
word = Boolean.parseBoolean(getXmlAttribute("prodata:wordIndex"));
|
1093 |
|
if (!readIndex(getXmlAttribute("name"), indexName, null, primary, true, word))
|
|
1167 |
if (!readIndex(getXmlAttribute("name"), indexName, nsPrefix, primary, true, word))
|
1094 |
1168 |
{
|
1095 |
1169 |
return false;
|
1096 |
1170 |
}
|
... | ... | |
1101 |
1175 |
indexName = getXmlAttribute("prodata:indexName");
|
1102 |
1176 |
primary = Boolean.parseBoolean(getXmlAttribute("prodata:primaryIndex"));
|
1103 |
1177 |
word = Boolean.parseBoolean(getXmlAttribute("prodata:wordIndex"));
|
1104 |
|
if (!readIndex(getXmlAttribute("name"), indexName, null, primary, false, word))
|
|
1178 |
if (!readIndex(getXmlAttribute("name"), indexName, nsPrefix, primary, false, word))
|
1105 |
1179 |
{
|
1106 |
1180 |
return false;
|
1107 |
1181 |
}
|
... | ... | |
1116 |
1190 |
|
1117 |
1191 |
// found a relation based on a unique index
|
1118 |
1192 |
indexName = getXmlAttribute("refer");
|
1119 |
|
P2JIndex uidx = uniqueIndexes.get(indexName);
|
|
1193 |
P2JIndex uidx = uniqueIndexes.get(removeNsPrefix(indexName));
|
1120 |
1194 |
if (uidx == null)
|
1121 |
1195 |
{
|
1122 |
1196 |
throw new XMLStreamException(
|
... | ... | |
1141 |
1215 |
case "selector":
|
1142 |
1216 |
if (keyrefRel != null)
|
1143 |
1217 |
{
|
1144 |
|
keyrefRel.setChild(getXmlAttribute("xpath"));
|
|
1218 |
keyrefRel.setChild(nsPrefix, getXmlAttribute("xpath"));
|
1145 |
1219 |
}
|
1146 |
1220 |
|
1147 |
1221 |
// otherwise, it is not related to unique index based relation
|
... | ... | |
1150 |
1224 |
case "field":
|
1151 |
1225 |
if (keyrefRel != null)
|
1152 |
1226 |
{
|
1153 |
|
keyrefRel.addChildField(getXmlAttribute("xpath"));
|
|
1227 |
keyrefRel.addChildField(nsPrefix, getXmlAttribute("xpath"));
|
1154 |
1228 |
}
|
1155 |
1229 |
|
1156 |
1230 |
// otherwise, it is not related to unique index based relation
|
... | ... | |
1171 |
1245 |
switch(name)
|
1172 |
1246 |
{
|
1173 |
1247 |
case ELEM_SCHEMA:
|
|
1248 |
processDsBuffers();
|
1174 |
1249 |
int numTables = ds.numBuffers().intValue();
|
1175 |
1250 |
if (verifySchemaMode == Verify.STRICT)
|
1176 |
1251 |
{
|
... | ... | |
1343 |
1418 |
|
1344 |
1419 |
throw new XMLStreamException("Unexpected EOS in readDatasetSchema().", reader.getLocation());
|
1345 |
1420 |
}
|
|
1421 |
|
|
1422 |
/**
|
|
1423 |
* Remove the namespace prefix from the qualified name
|
|
1424 |
*
|
|
1425 |
* @param qname
|
|
1426 |
* qualified name to be simplified
|
|
1427 |
*
|
|
1428 |
* @return name w/o prefix
|
|
1429 |
*/
|
|
1430 |
private String removeNsPrefix(String qname)
|
|
1431 |
{
|
|
1432 |
int pos = qname.indexOf(':');
|
|
1433 |
return pos > 0 ? qname.substring(pos+1) : qname;
|
|
1434 |
|
|
1435 |
}
|
|
1436 |
/**
|
|
1437 |
* Process buffers for the found dataset tables.
|
|
1438 |
*/
|
|
1439 |
private void processDsBuffers()
|
|
1440 |
{
|
|
1441 |
BufferImpl[] dsBuffers = new BufferImpl[tables.size()];
|
|
1442 |
int nb = 0;
|
|
1443 |
for (Map.Entry<String, AbstractTempTable> e: tables.entrySet())
|
|
1444 |
{
|
|
1445 |
TempTableBuilder ttb = (TempTableBuilder)e.getValue();
|
|
1446 |
ttb.tempTablePrepare(e.getKey());
|
|
1447 |
Buffer tbuffer = ttb.defaultBufferHandle().unwrapBuffer();
|
|
1448 |
if (tbuffer != null)
|
|
1449 |
{
|
|
1450 |
dsBuffers[nb++] = (BufferImpl)tbuffer;
|
|
1451 |
}
|
|
1452 |
}
|
|
1453 |
ds.setBuffers(dsBuffers);
|
|
1454 |
}
|
1346 |
1455 |
|
1347 |
1456 |
/**
|
1348 |
1457 |
* Reads and processes an {@code AbstractTempTable} schema. If the {@code TempTable} is in CLEAR state, the
|
... | ... | |
1379 |
1488 |
}
|
1380 |
1489 |
|
1381 |
1490 |
name = reader.getLocalName();
|
1382 |
|
|
1383 |
1491 |
// index properties:
|
1384 |
1492 |
String indexName = null;
|
1385 |
1493 |
boolean primary = false;
|
... | ... | |
1389 |
1497 |
{
|
1390 |
1498 |
case "element":
|
1391 |
1499 |
boolean isTT = Boolean.parseBoolean(getXmlAttribute("prodata:proTempTable"));
|
1392 |
|
if (isTT)
|
|
1500 |
if (isTT || external)
|
1393 |
1501 |
{
|
1394 |
1502 |
String tableName = getXmlAttribute("prodata:tableName");
|
1395 |
1503 |
if (tableName == null)
|
... | ... | |
1408 |
1516 |
undo = Boolean.parseBoolean(getXmlAttribute("prodata:undo"));
|
1409 |
1517 |
|
1410 |
1518 |
ttName = tableName;
|
|
1519 |
ttPrefix = nsPrefix;
|
1411 |
1520 |
if (!readTableSchema(tableName, nsPrefix))
|
1412 |
1521 |
{
|
1413 |
1522 |
return false;
|
... | ... | |
1479 |
1588 |
{
|
1480 |
1589 |
ttb.namespaceURI(nsUri);
|
1481 |
1590 |
}
|
1482 |
|
if (!ttb.tempTablePrepare(ttName).booleanValue())
|
|
1591 |
if (!external && !ttb.tempTablePrepare(ttName).booleanValue())
|
1483 |
1592 |
{
|
1484 |
1593 |
// TODO: report error? already reported?
|
1485 |
1594 |
return false;
|
... | ... | |
1561 |
1670 |
xpath = xpath.substring(3);
|
1562 |
1671 |
}
|
1563 |
1672 |
|
1564 |
|
if (nsPrefix != null && xpath.startsWith(nsPrefix))
|
1565 |
|
{
|
1566 |
|
// drop the [nsPrefix], including the COLON, if any
|
1567 |
|
xpath = xpath.substring(nsPrefix.length() + 1);
|
1568 |
|
}
|
|
1673 |
xpath = removeNsPrefix(xpath);
|
1569 |
1674 |
|
1570 |
1675 |
if (tablesByXmlName != null)
|
1571 |
1676 |
{
|
... | ... | |
1600 |
1705 |
break;
|
1601 |
1706 |
|
1602 |
1707 |
case "field":
|
1603 |
|
String field = getXmlAttribute(unique ? "xpath" : "name");
|
1604 |
|
if (nsPrefix != null && field.startsWith(nsPrefix))
|
1605 |
|
{
|
1606 |
|
// drop the [nsPrefix], including the COLON, if any
|
1607 |
|
field = field.substring(nsPrefix.length() + 1);
|
1608 |
|
}
|
|
1708 |
String field = removeNsPrefix(getXmlAttribute(unique ? "xpath" : "name"));
|
1609 |
1709 |
boolean desc = Boolean.parseBoolean(getXmlAttribute("prodata:descending"));
|
1610 |
1710 |
if (ttb != null && !ttb._prepared())
|
1611 |
1711 |
{
|
... | ... | |
2934 |
3034 |
/**
|
2935 |
3035 |
* Sets the name of the child buffer. If needed the {@code "..//"} prefix is dropped.
|
2936 |
3036 |
*
|
|
3037 |
* @param nsPrefix
|
|
3038 |
* namespace prefix.
|
|
3039 |
*
|
2937 |
3040 |
* @param xpath
|
2938 |
3041 |
* The name of the child buffer, as read from XML.
|
2939 |
3042 |
*/
|
2940 |
|
public void setChild(String xpath)
|
|
3043 |
public void setChild(String nsPrefix, String xpath)
|
2941 |
3044 |
{
|
2942 |
|
child = xpath.startsWith(".//") ? xpath.substring(3) : xpath;
|
|
3045 |
if (xpath.startsWith(".//"))
|
|
3046 |
{
|
|
3047 |
xpath = xpath.substring(3);
|
|
3048 |
}
|
|
3049 |
if (nsPrefix != null && xpath.startsWith(nsPrefix))
|
|
3050 |
{
|
|
3051 |
xpath = xpath.substring(nsPrefix.length() + 1);
|
|
3052 |
}
|
|
3053 |
|
|
3054 |
child = xpath;
|
2943 |
3055 |
}
|
2944 |
3056 |
|
2945 |
3057 |
/**
|
2946 |
3058 |
* Adds a new field to be used on child side of the relation.
|
2947 |
|
*
|
|
3059 |
* @param nsPrefix
|
|
3060 |
* namespace prefix
|
|
3061 |
*
|
2948 |
3062 |
* @param field
|
2949 |
3063 |
* The name of the field.
|
2950 |
3064 |
*/
|
2951 |
|
public void addChildField(String field)
|
|
3065 |
public void addChildField(String nsPrefix, String field)
|
2952 |
3066 |
{
|
2953 |
|
childFields.add(field);
|
|
3067 |
childFields.add(nsPrefix != null && field.startsWith(nsPrefix) ?
|
|
3068 |
field.substring(nsPrefix.length() + 1) :
|
|
3069 |
field);
|
2954 |
3070 |
}
|
2955 |
3071 |
|
2956 |
3072 |
/**
|