Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,13 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](http://keepachangelog.com/).
====================

# 5.5.0 - 2026-02-06

## Added

- support for row creation time
- support for last write metadata of a row

# 5.4.3 - 2025-08-15

## Fixed
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2018, 2025 Oracle and/or its affiliates.
Copyright (c) 2018, 2026 Oracle and/or its affiliates.

The Universal Permissive License (UPL), Version 1.0

Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ install the oci package::

pip install oci

See [the installation guide](https://nosql-python-sdk.readthedocs.io/en/stable/installation.html) for additional requirements and and alternative install
See [the installation guide](https://nosql-python-sdk.readthedocs.io/en/stable/installation.html) for additional requirements and alternative install
methods.

## Examples
Expand Down Expand Up @@ -81,7 +81,7 @@ that the *borneo* package has been installed.
``` python

#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down Expand Up @@ -405,7 +405,7 @@ operate correctly. A secure configuration requires a secure proxy and more
complex configuration.

1. Start the Oracle NoSQL Database and proxy server based on instructions above.
Note the HTTP port used. By default the endpoint is *localhost:80*.
Note the HTTP port used. By default, the endpoint is *localhost:80*.

2. The *quickstart.py* program defaults to *localhost:80*. If the proxy was
started using a different host or port edit the settings accordingly.
Expand All @@ -426,7 +426,7 @@ Please consult the [security guide](./SECURITY.md) for our responsible security

## License

Copyright (c) 2018, 2025 Oracle and/or its affiliates.
Copyright (c) 2018, 2026 Oracle and/or its affiliates.

Released under the Universal Permissive License v1.0 as shown at
<https://oss.oracle.com/licenses/upl/>.
2 changes: 1 addition & 1 deletion examples/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/config_cloud.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/config_cloudsim.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/config_onprem.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/multi_data_ops.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/parameters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/rate_limiting.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/single_data_ops.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/table_ops.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion examples/utils.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/auth.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
45 changes: 43 additions & 2 deletions src/borneo/client.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand All @@ -22,6 +22,7 @@
OperationNotSupportedException, RequestSizeLimitException)
from .http import RateLimiterMap, RequestUtils
from .kv import StoreAccessTokenProvider
from .nson_protocol import LAST_WRITE_METADATA
from .operations import (
GetTableRequest, QueryRequest, QueryResult, TableRequest, WriteRequest)
from .query import QueryDriver
Expand All @@ -35,6 +36,10 @@ class Client(object):
LIMITER_REFRESH_NANOS = 600000000000
TRACE_LEVEL = 0

# proxy enabled features flag bits, works on this._features
# Features: added in KV 26.1, SDK 5.4.4
FEATURE_FLAG_LAST_WRITE_METADATA = 1 << 0

# The HTTP driver client.
def __init__(self, config, logger):
self._logutils = LogUtils(logger)
Expand Down Expand Up @@ -117,6 +122,9 @@ def __init__(self, config, logger):
self._stats_control = StatsControl(config,
logger,
config.get_rate_limiting_enabled())
# Keeps a set of bits each one corresponding to an enabled feature
# signaled by the httpproxy. See FEATURE_FLAG_LAST_WRITE_METADATA.
self._features = 0

@synchronized
def background_update_limiters(self, table_name):
Expand Down Expand Up @@ -178,6 +186,13 @@ def execute(self, request):
CheckValue.check_not_none(request, 'request')
request.set_defaults(self._config)
request.validate()

if (request.get_last_write_metadata() is not None) and \
(not self.is_feature_enabled(
self.FEATURE_FLAG_LAST_WRITE_METADATA)):
raise OperationNotSupportedException('Last Write Metadata is not' +
'supported on this server')

if request.is_query_request():
self._stats_control.observe_query(request)

Expand Down Expand Up @@ -592,9 +607,35 @@ def get_kv_version(self):
return self._kv_version

def set_proxy_info(self, proxy_header):
"""
Format of the server version header string:
proxy=X.Y.Z kv=X.Y.Z[ features=XX]

If "features" exists, its value is a long in hex.
"""
if self._proxy_version is None and proxy_header is not None:
versions = proxy_header.split()
# bail if not of correct format
if len(versions) == 2:
if len(versions) >= 2:
self._proxy_version = versions[0].split('=')[1]
self._kv_version = versions[1].split('=')[1]
if (len(versions) >= 3 and
versions[2].split('=')[0] == 'features' and
len(versions[2].split('=')[1]) <= 16 ):
feat_str = versions[2].split('=')[1]
try:
self._features = int(feat_str, base=16)
except ValueError:
self._logutils.log_info(
f"Received invalid features flag from server: {feat_str}")

def is_feature_enabled(self, feature_flag):
if self._proxy_version is None:
# there were no requests until now
request_utils = RequestUtils(
self._sess, self._logutils, None, self._retry_handler,
self, self._rate_limiter_map)
request_utils.do_head_request(self._request_uri, {},
self._config.get_default_timeout())

return (self._features & feature_flag) != 0
10 changes: 9 additions & 1 deletion src/borneo/common.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down Expand Up @@ -232,6 +232,14 @@ def check_str(data, name, allow_none=False):
raise IllegalArgumentException(
name + ' must be a string that is not empty.')

@staticmethod
def check_json_construct(data, name):
if not(data is None or isinstance(data, dict) or isinstance(data, list)
or isinstance(data, str) or isinstance(data, int) or
isinstance(data, float) or isinstance(data, Decimal) or
isinstance(data, bool)):
raise IllegalArgumentException(name + ' must be a jason construct.')

@staticmethod
def is_digit(data):
if (isinstance(data, int) or
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/config.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/driver.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/exception.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
27 changes: 25 additions & 2 deletions src/borneo/http.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down Expand Up @@ -172,6 +172,28 @@ def do_put_request(self, uri, headers, payload, timeout_ms):
"""
return self._do_request('PUT', uri, headers, payload, timeout_ms, None)

def do_head_request(self, uri, headers, timeout_ms):
"""
Issue HTTP HEAD request with retries and general error handling.

It retries upon seeing following exceptions and response codes:

HTTP response with status code larger than 500\n
Other throwable excluding RuntimeException, InterruptedException,
ExecutionException and TimeoutException

:param uri: the request URI.
:type uri: str
:param headers: HTTP headers of this request.
:type headers: dict
:param timeout_ms: request timeout in milliseconds.
:type timeout_ms: int
:returns: HTTP response, a object encapsulate status code and response.
:rtype: HttpResponse or Result
"""
return self._do_request('HEAD', uri, headers, None, timeout_ms, None)


def _do_request(self, method, uri, headers, payload, timeout_ms,
stats_config):
exception = None
Expand Down Expand Up @@ -290,9 +312,10 @@ def _do_request(self, method, uri, headers, payload, timeout_ms,
self._logutils.log_debug(
'Response: ' + self._request.__class__.__name__ +
', status: ' + str(response.status_code))
if self._request is not None:
if self._client is not None:
self._client.set_proxy_info(
response.headers.get(HttpConstants.RESPONSE_PROXY_INFO))
if self._request is not None:
res = self._process_response(
self._request, response.content, response.status_code)
# set server's serial version if available
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/iam/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/iam/iam.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/kv/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/kv/exception.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
2 changes: 1 addition & 1 deletion src/borneo/kv/kv.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2025 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2026 Oracle and/or its affiliates. All rights reserved.
#
# Licensed under the Universal Permissive License v 1.0 as shown at
# https://oss.oracle.com/licenses/upl/
Expand Down
Loading