Skip to content

Commit f11a99f

Browse files
committed
Merge branch 'main' into feat/bundle-functions
2 parents 582c253 + 0052967 commit f11a99f

4 files changed

Lines changed: 50 additions & 87 deletions

File tree

crates/core/src/expr/indexed_field.rs

Lines changed: 0 additions & 82 deletions
This file was deleted.

crates/core/src/expr/join.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ impl Display for PyJoinType {
6262
}
6363
}
6464

65-
#[derive(Debug, Clone, Copy)]
65+
#[derive(Debug, Clone)]
6666
#[pyclass(
6767
from_py_object,
6868
frozen,

docs/source/user-guide/data-sources.md

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,9 @@ ctx.create_dataframe([[batch]]).show()
8989
## Object Store
9090

9191
DataFusion has support for multiple storage options in addition to local files.
92-
The example below requires an appropriate S3 account with access credentials.
92+
The example below requires access to the S3 bucket. Set `AWS_ACCESS_KEY_ID` and
93+
`AWS_SECRET_ACCESS_KEY` in the environment before running it. For temporary
94+
credentials, also set `AWS_SESSION_TOKEN`.
9395

9496
Supported Object Stores are
9597

@@ -100,16 +102,17 @@ Supported Object Stores are
100102
- {py:class}`~datafusion.object_store.MicrosoftAzure`
101103

102104
```python
105+
from datafusion import SessionContext
103106
from datafusion.object_store import AmazonS3
104107

105108
region = "us-east-1"
106109
bucket_name = "yellow-trips"
107110

111+
ctx = SessionContext()
112+
108113
s3 = AmazonS3(
109114
bucket_name=bucket_name,
110115
region=region,
111-
access_key_id=os.getenv("AWS_ACCESS_KEY_ID"),
112-
secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"),
113116
)
114117

115118
path = f"s3://{bucket_name}/"
@@ -120,6 +123,27 @@ ctx.register_parquet("trips", path)
120123
ctx.table("trips").show()
121124
```
122125

126+
### Query S3 data with SQL
127+
128+
To reach the same data from SQL, give the S3 path a table name with
129+
`CREATE EXTERNAL TABLE`. The registered object store carries the credentials and
130+
the region, so the statement itself needs only the location.
131+
132+
Register the store for the bucket as shown above, then use that same
133+
{py:class}`~datafusion.context.SessionContext` to create and query the table:
134+
135+
```python
136+
ctx.sql(
137+
f"""
138+
CREATE EXTERNAL TABLE trips_sql
139+
STORED AS PARQUET
140+
LOCATION '{path}'
141+
"""
142+
).collect()
143+
144+
ctx.sql("SELECT count(passenger_count) FROM trips_sql").show()
145+
```
146+
123147
## Other DataFrame Libraries
124148

125149
DataFusion can import DataFrames directly from other libraries, such as

python/tests/test_object_store_param.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
"""Tests for the object_store parameter on register/read file methods."""
18+
"""Tests for object store registration and register/read file methods."""
1919

2020
import contextlib
2121
from pathlib import Path
@@ -138,3 +138,24 @@ def test_parquet_methods_with_local_object_store(ctx, tmp_path, method_name):
138138
dataframe = ctx.read_parquet(path, object_store=LocalFileSystem())
139139

140140
assert dataframe.collect()[0].column("value").to_pylist() == [10, 20, 30]
141+
142+
143+
def test_sql_external_table_uses_registered_object_store(ctx, tmp_path):
144+
"""Read a remote URL through a registered store without network access."""
145+
table = pa.table({"passenger_count": [1, None, 3]})
146+
pq.write_table(table, tmp_path / "trips.parquet")
147+
148+
# Back the S3 URL with local files to test SQL's registry lookup, not AWS.
149+
store = LocalFileSystem(prefix=str(tmp_path))
150+
ctx.register_object_store("s3://", store, host="test-bucket")
151+
ctx.sql(
152+
"""
153+
CREATE EXTERNAL TABLE trips_sql
154+
STORED AS PARQUET
155+
LOCATION 's3://test-bucket/'
156+
"""
157+
).collect()
158+
159+
assert ctx.table("trips_sql").to_pydict() == table.to_pydict()
160+
result = ctx.sql("SELECT count(passenger_count) AS count FROM trips_sql")
161+
assert result.to_pydict() == {"count": [2]}

0 commit comments

Comments
 (0)