Skip to content

Commit 103b9c7

Browse files
authored
Merge pull request #35 from VedantMahajanOracle/XDK_SODA1_LINUX.X64_241016
updating to 241016
2 parents 50fca4c + 57638bc commit 103b9c7

File tree

9 files changed

+971
-73
lines changed

9 files changed

+971
-73
lines changed

orajsoda/src/main/java/oracle/json/parser/AndORTree.java

Lines changed: 149 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
*/
1919
package oracle.json.parser;
2020

21+
import java.io.ByteArrayOutputStream;
2122
import java.io.InputStream;
2223
import java.math.BigDecimal;
2324
import java.sql.PreparedStatement;
@@ -47,6 +48,8 @@
4748
import oracle.json.common.JsonFactoryProvider;
4849
import oracle.json.parser.Evaluator.EvaluatorCode;
4950
import oracle.sql.json.OracleJsonValue;
51+
import oracle.sql.json.OracleJsonFactory;
52+
import oracle.sql.json.OracleJsonGenerator;
5053
import oracle.sql.json.OracleJsonString;
5154
import oracle.sql.json.OracleJsonTimestampTZ;
5255

@@ -867,12 +870,22 @@ public void appendJsonExists(StringBuilder output, boolean isTreatAsAvailable)
867870
appendJsonExists(output, null, 0, isTreatAsAvailable);
868871
}
869872

870-
public int appendJsonExists(StringBuilder output, String tokenFormat, int startingTokenIndex, boolean isTreatAsAvailable)
873+
public int appendJsonExists(StringBuilder output, String tokenFormat, int startingTokenIndex,
874+
boolean isTreatAsAvailable)
875+
{
876+
return appendJsonExists(output, tokenFormat, startingTokenIndex, isTreatAsAvailable, true, null);
877+
}
878+
879+
public int appendJsonExists(StringBuilder output, String tokenFormat, int startingTokenIndex,
880+
boolean isTreatAsAvailable, boolean allowBinds, OracleJsonFactory factory)
871881
{
872882
// Assumes that this method is invoked only if hasJsonExists()
873883
// returns true. So jsonExists cannot be null here.
874884
if (jsonExists == null)
875885
throw new IllegalStateException();
886+
887+
if ((tokenFormat != null || startingTokenIndex != 0) && (!allowBinds))
888+
throw new IllegalStateException();
876889

877890
int tokenCount = 0;
878891

@@ -883,64 +896,139 @@ public int appendJsonExists(StringBuilder output, String tokenFormat, int starti
883896
output.append("'");
884897

885898
int numBinds = getNumVals();
886-
if (numBinds > 0)
887-
{
899+
if (numBinds > 0) {
888900
output.append(" passing ");
889901

890-
for (int varNum = 0; varNum < numBinds; ++varNum)
891-
{
902+
for (int varNum = 0; varNum < numBinds; ++varNum) {
892903
if (tokenFormat != null)
893904
token = String.format(tokenFormat, startingTokenIndex);
894905
ValueTypePair vpair = valueArray.get(varNum);
895906

896907
if (varNum > 0)
897908
output.append(", ");
898909

899-
if (vpair.isTimestamp())
900-
{
901-
// This format can consume trailing timezones including a "Z"
902-
// but only if it's used with TO_TIMESTAMP_TZ.
903-
output.append("TO_TIMESTAMP_TZ(");
904-
output.append(token);
905-
output.append(",'SYYYY-MM-DD\"T\"HH24:MI:SS.FFTZH:TZM')");
910+
if (allowBinds) {
911+
appendBindValue(vpair, output, token, isTreatAsAvailable);
912+
tokenCount++;
913+
} else {
914+
appendInlineBindValueExpression(vpair.value, output, factory);
906915
}
907-
else if (vpair.isDate())
908-
{
909-
// This format includes the time component to reliably consume
910-
// Oracle date+time values, but should also work if the time is
911-
// not present in the bind variable.
912-
output.append("TO_DATE(");
913-
output.append(token);
914-
output.append("?,'SYYYY-MM-DD\"T\"HH24:MI:SS')");
915-
}
916-
else if (isTreatAsAvailable && vpair.isObject())
917-
{
918-
output.append("treat(");
919-
output.append(token);
920-
output.append(" as json(object))");
921-
}
922-
else if (isTreatAsAvailable && vpair.isArray())
923-
{
924-
output.append("treat(");
925-
output.append(token);
926-
output.append(" as json(array))");
927-
}
928-
else
929-
output.append(token);
930-
931-
tokenCount++;
932916

933917
output.append(" as \"B");
934918
output.append(Integer.toString(varNum));
935919
output.append("\"");
936-
937-
startingTokenIndex++;
920+
921+
if (allowBinds)
922+
startingTokenIndex++;
938923
}
939924
}
940925

941926
return tokenCount;
942927
}
943928

929+
private String getOsonHex(OracleJsonValue bind, OracleJsonFactory factory) {
930+
ByteArrayOutputStream baos = new ByteArrayOutputStream();
931+
OracleJsonGenerator gen = factory.createJsonBinaryGenerator(baos);
932+
gen.write(bind);
933+
gen.close();
934+
byte[] oson = baos.toByteArray();
935+
String hex = ByteArray.rawToHex(oson);
936+
return hex;
937+
}
938+
939+
private void appendValueAsSQLType(String returnType, StringBuilder sql, String hex) {
940+
if (returnType != null)
941+
sql.append("json_value(json(hextoraw('").append(hex).append("')), '$' returning ").append(returnType).append(")");
942+
else
943+
sql.append("json(hextoraw('").append(hex).append("'))");
944+
}
945+
946+
private void appendInlineBindValueExpression(JsonValue value, StringBuilder sql, OracleJsonFactory factory) {
947+
OracleJsonValue ovalue = null;
948+
try {
949+
Wrapper wrapper;
950+
if (!(value instanceof Wrapper) || !((wrapper = (Wrapper) value)).isWrapperFor(OracleJsonValue.class)) {
951+
// infeasible as allowBinds is only false when input filter is oson
952+
throw new UnsupportedOperationException();
953+
}
954+
ovalue = wrapper.unwrap(OracleJsonValue.class);
955+
} catch (SQLException e) {
956+
// infeasible
957+
throw new IllegalStateException(e);
958+
}
959+
String hex = getOsonHex(ovalue, factory);
960+
switch (ovalue.getOracleJsonType()) {
961+
case ARRAY:
962+
case NULL:
963+
case OBJECT:
964+
case TRUE:
965+
case FALSE:
966+
appendValueAsSQLType(null, sql, hex);
967+
break;
968+
case BINARY:
969+
if (ovalue.asJsonBinary().isId())
970+
appendValueAsSQLType(null, sql, hex);
971+
else
972+
appendValueAsSQLType("raw", sql, hex);
973+
break;
974+
case DATE:
975+
appendValueAsSQLType("date", sql, hex);
976+
break;
977+
case DECIMAL:
978+
appendValueAsSQLType("number", sql, hex);
979+
break;
980+
case DOUBLE:
981+
appendValueAsSQLType("double precision", sql, hex);
982+
break;
983+
case FLOAT:
984+
appendValueAsSQLType("float", sql, hex);
985+
break;
986+
case INTERVALDS:
987+
appendValueAsSQLType("interval day to second", sql, hex);
988+
break;
989+
case INTERVALYM:
990+
appendValueAsSQLType("interval year to month", sql, hex);
991+
break;
992+
case STRING:
993+
appendValueAsSQLType("varchar2", sql, hex);
994+
break;
995+
case TIMESTAMP:
996+
appendValueAsSQLType("timestamp", sql, hex);
997+
break;
998+
case TIMESTAMPTZ:
999+
appendValueAsSQLType("timestamp with time zone", sql, hex);
1000+
break;
1001+
default:
1002+
throw new IllegalStateException();
1003+
}
1004+
}
1005+
1006+
private void appendBindValue(ValueTypePair vpair, StringBuilder output, String token, boolean isTreatAsAvailable) {
1007+
if (vpair.isTimestamp()) {
1008+
// This format can consume trailing timezones including a "Z"
1009+
// but only if it's used with TO_TIMESTAMP_TZ.
1010+
output.append("TO_TIMESTAMP_TZ(");
1011+
output.append(token);
1012+
output.append(",'SYYYY-MM-DD\"T\"HH24:MI:SS.FFTZH:TZM')");
1013+
} else if (vpair.isDate()) {
1014+
// This format includes the time component to reliably consume
1015+
// Oracle date+time values, but should also work if the time is
1016+
// not present in the bind variable.
1017+
output.append("TO_DATE(");
1018+
output.append(token);
1019+
output.append("?,'SYYYY-MM-DD\"T\"HH24:MI:SS')");
1020+
} else if (isTreatAsAvailable && vpair.isObject()) {
1021+
output.append("treat(");
1022+
output.append(token);
1023+
output.append(" as json(object))");
1024+
} else if (isTreatAsAvailable && vpair.isArray()) {
1025+
output.append("treat(");
1026+
output.append(token);
1027+
output.append(" as json(array))");
1028+
} else
1029+
output.append(token);
1030+
}
1031+
9441032
/*
9451033
* Append a bind variable for a SQL JSON operator,
9461034
* with an optional format wrapper
@@ -1082,13 +1170,15 @@ public boolean hasFilterSpec()
10821170
hasSqlJsonClause();
10831171
}
10841172

1085-
public boolean appendFilterSpec(StringBuilder sb, boolean append,
1086-
String columnName, String inputFormatClause,
1087-
boolean isTreatAsAvailable)
1088-
throws QueryException
1089-
{
1173+
public boolean appendFilterSpec(StringBuilder sb, boolean append, String columnName, String inputFormatClause,
1174+
boolean isTreatAsAvailable) throws QueryException {
1175+
return appendFilterSpec(sb, append, columnName, inputFormatClause, isTreatAsAvailable, true, null);
1176+
}
1177+
1178+
public boolean appendFilterSpec(StringBuilder sb, boolean append, String columnName, String inputFormatClause,
1179+
boolean isTreatAsAvailable, boolean allowBinds, OracleJsonFactory factory) throws QueryException {
10901180
int length = sb.length();
1091-
appendFilterSpec(sb, append, columnName, inputFormatClause, null, 0, isTreatAsAvailable);
1181+
appendFilterSpec(sb, append, columnName, inputFormatClause, null, 0, isTreatAsAvailable, allowBinds, factory);
10921182

10931183
if (sb.length() == length) {
10941184
if (append == true)
@@ -1098,12 +1188,20 @@ public boolean appendFilterSpec(StringBuilder sb, boolean append,
10981188
}
10991189
return true;
11001190
}
1191+
1192+
1193+
//Not part of a public API. Needs to be public for use from REST layer.
1194+
public int appendFilterSpec(StringBuilder sb, boolean append, String columnName, String inputFormatClause,
1195+
String format, int startingIndex, boolean isTreatAsAvailable) throws QueryException {
1196+
return appendFilterSpec(sb, append, columnName, inputFormatClause, format, startingIndex, isTreatAsAvailable, true, null);
1197+
}
11011198

1102-
// Not part of a public API. Needs to be public for use from REST layer.
1199+
//Not part of a public API
11031200
public int appendFilterSpec(StringBuilder sb, boolean append,
11041201
String columnName, String inputFormatClause,
11051202
String format, int startingIndex,
1106-
boolean isTreatAsAvailable) throws QueryException
1203+
boolean isTreatAsAvailable, boolean allowBinds,
1204+
OracleJsonFactory factory) throws QueryException
11071205
{
11081206
int tokenCount = 0;
11091207

@@ -1116,7 +1214,7 @@ public int appendFilterSpec(StringBuilder sb, boolean append,
11161214
if (hasJsonExists())
11171215
{
11181216
appendAnd(sb, append);
1119-
tokenCount = appendFilterSpecJsonExists(sb, columnName, inputFormatClause, format, startingIndex, isTreatAsAvailable);
1217+
tokenCount = appendFilterSpecJsonExists(sb, columnName, inputFormatClause, format, startingIndex, isTreatAsAvailable, allowBinds, factory);
11201218
append = true;
11211219
}
11221220

@@ -1159,7 +1257,8 @@ public int appendFilterSpec(StringBuilder sb, boolean append,
11591257

11601258
private int appendFilterSpecJsonExists(StringBuilder sb, String columnName,
11611259
String inputFormatClause, String tokenFormat,
1162-
int startingTokenIndex, boolean isTreatAsAvailable)
1260+
int startingTokenIndex, boolean isTreatAsAvailable,
1261+
boolean allowBinds, OracleJsonFactory factory)
11631262
{
11641263
int tokenCount = 0;
11651264
sb.append("JSON_EXISTS(");
@@ -1169,7 +1268,7 @@ private int appendFilterSpecJsonExists(StringBuilder sb, String columnName,
11691268
}
11701269

11711270
sb.append(",");
1172-
tokenCount = appendJsonExists(sb, tokenFormat, startingTokenIndex, isTreatAsAvailable);
1271+
tokenCount = appendJsonExists(sb, tokenFormat, startingTokenIndex, isTreatAsAvailable, allowBinds, factory);
11731272
if (this.strictTypeMode) {
11741273
sb.append(" type(strict)");
11751274
}

orajsoda/src/main/java/oracle/soda/OracleDocument.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2023, Oracle and/or its affiliates. */
1+
/* Copyright (c) 2014, 2024, Oracle and/or its affiliates. */
22
/* All rights reserved.*/
33

44
package oracle.soda;
@@ -17,6 +17,10 @@
1717
* <li>version or checksum (suitable for ETag)
1818
* <li>media type ("application/json" for JSON documents)
1919
* </ul>
20+
* <p>
21+
* created-on and last-modified timestamps are not tracked for
22+
* collections based on JSON Collection Tables and Duality Views (introduced in Oracle Database 23ai).
23+
* For such collections these values are null.
2024
* <P>
2125
* It is valid for any of the above components to be missing in
2226
* a given <code>OracleDocument</code>.
@@ -85,7 +89,9 @@ String getContentAsString()
8589
* <th style="border: 1px solid black; padding: 5px;">Description</th>
8690
* </tr>
8791
* <tr>
88-
* <td style="border: 1px solid black; padding: 5px;">{@code javax.json.JsonValue}<br>
92+
* <td style="border: 1px solid black; padding: 5px;">
93+
* {@code javax.json.JsonValue}<br>
94+
* {@code jakarta.json.JsonValue}<br>
8995
* {@code oracle.sql.json.OracleJsonValue}
9096
* </td>
9197
* <td style="border: 1px solid black; padding: 5px;">The JSON type value is returned as {@code JsonValue} or {@code OracleJsonValue}.
@@ -95,6 +101,7 @@ String getContentAsString()
95101
* <tr>
96102
* <td style="border: 1px solid black; padding: 5px;">
97103
* {@code javax.json.stream.JsonParser}<br>
104+
* {@code jakarta.json.stream.JsonParser}<br>
98105
* {@code oracle.sql.json.OracleJsonParser}
99106
* </td>
100107
* <td style="border: 1px solid black; padding: 5px;">
@@ -112,7 +119,7 @@ String getContentAsString()
112119
* <td style="border: 1px solid black; padding: 5px;">The JSON type value is returned as UTF8 JSON text. </td>
113120
* </tr>
114121
* </table>
115-
*
122+
* <b>Deprecation Notice:</b> support for {@code javax.json} will be removed in an upcoming release.
116123
*
117124
* @param <T> the type of the returned content
118125
* @param type the type of the returned content
@@ -140,6 +147,8 @@ <T> T getContentAs(Class<T> type)
140147
/**
141148
* Returns the timestamp of the last modification to this document in
142149
* ISO format.
150+
* <code>null</code> for collections based on JSON Collection
151+
* Tables and Duality Views (introduced in Oracle Database 23ai).
143152
*
144153
* @return a <code>String</code> representation of the
145154
* timestamp, or <code>null</code> if the timestamp
@@ -149,6 +158,8 @@ <T> T getContentAs(Class<T> type)
149158

150159
/**
151160
* Returns the timestamp of creation of this document in ISO format.
161+
* <code>null</code> for collections based on JSON Collection
162+
* Tables and Duality Views (introduced in Oracle Database 23ai).
152163
*
153164
* @return a <code>String</code> representation of the
154165
* timestamp, or <code>null</code> if the timestamp

orajsoda/src/main/java/oracle/soda/OracleDocumentFactory.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2023, Oracle and/or its affiliates. */
1+
/* Copyright (c) 2014, 2024, Oracle and/or its affiliates. */
22
/* All rights reserved.*/
33

44
package oracle.soda;
@@ -116,6 +116,7 @@ OracleDocument createDocumentFrom(Object content)
116116
* <tr>
117117
* <td style="border: 1px solid black; padding: 5px;">
118118
* {@code javax.json.JsonValue}<br>
119+
* {@code jakarta.json.JsonValue}<br>
119120
* {@code oracle.sql.json.OracleJsonValue}
120121
* </td>
121122
* <td style="border: 1px solid black; padding: 5px;"> A instance of {@code JsonValue} or {@code OracleJsonValue}. This includes derivations
@@ -133,6 +134,7 @@ OracleDocument createDocumentFrom(Object content)
133134
* <tr>
134135
* <td style="border: 1px solid black; padding: 5px;">
135136
* {@code javax.json.stream.JsonParser}<br>
137+
* {@code jakarta.json.stream.JsonParser}<br>
136138
* {@code oracle.sql.json.OracleJsonParser}
137139
* </td>
138140
* <td style="border: 1px solid black; padding: 5px;">
@@ -154,6 +156,7 @@ OracleDocument createDocumentFrom(Object content)
154156
* </td>
155157
* </tr>
156158
* </table>
159+
* <b>Deprecation Notice:</b> support for {@code javax.json} will be removed in an upcoming release.
157160
*
158161
* @see <a href="https://javaee.github.io/jsonp/">Java API for JSON Processing</a>
159162
*

0 commit comments

Comments
 (0)