laurentgo commented on code in PR #2401:
URL: https://github.com/apache/arrow-adbc/pull/2401#discussion_r1909127204


##########
java/driver/jni/pom.xml:
##########
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing,
+  software distributed under the License is distributed on an
+  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+  KIND, either express or implied.  See the License for the
+  specific language governing permissions and limitations
+  under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.apache.arrow.adbc</groupId>
+    <artifactId>arrow-adbc-java-root</artifactId>
+    <version>0.16.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+
+  <artifactId>adbc-driver-jni</artifactId>
+  <packaging>jar</packaging>
+  <name>Arrow ADBC Driver Native</name>
+  <description>An ADBC driver wrapping the native driver manager.</description>
+
+  <dependencies>
+    <!-- Arrow -->
+    <dependency>
+      <groupId>org.apache.arrow</groupId>
+      <artifactId>arrow-c-data</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.arrow</groupId>
+      <artifactId>arrow-memory-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.arrow</groupId>
+      <artifactId>arrow-vector</artifactId>
+    </dependency>
+
+    <dependency>
+      <groupId>org.apache.arrow.adbc</groupId>
+      <artifactId>adbc-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.arrow.adbc</groupId>
+      <artifactId>adbc-driver-manager</artifactId>
+    </dependency>
+
+    <!-- Static analysis and linting -->
+    <dependency>
+      <groupId>org.checkerframework</groupId>
+      <artifactId>checker-qual</artifactId>
+    </dependency>
+
+    <!-- Testing -->
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>

Review Comment:
   if tests are using junit5, is the vintage engine needed?



##########
java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/JniDriver.java:
##########
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.arrow.adbc.driver.jni;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import org.apache.arrow.adbc.core.AdbcDatabase;
+import org.apache.arrow.adbc.core.AdbcDriver;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.adbc.core.TypedKey;
+import org.apache.arrow.adbc.driver.jni.impl.JniLoader;
+import org.apache.arrow.adbc.driver.jni.impl.NativeHandle;
+import org.apache.arrow.memory.BufferAllocator;
+
+/** An ADBC driver wrapping Arrow Flight SQL. */
+public class JniDriver implements AdbcDriver {
+  public static final TypedKey<String> PARAM_DRIVER = new 
TypedKey<>("jni.driver", String.class);
+
+  private final BufferAllocator allocator;
+
+  public JniDriver(BufferAllocator allocator) {
+    this.allocator = Objects.requireNonNull(allocator);
+  }
+
+  @Override
+  public AdbcDatabase open(Map<String, Object> parameters) throws 
AdbcException {
+    String driverName = PARAM_DRIVER.get(parameters);
+    if (driverName == null) {
+      throw AdbcException.invalidArgument(
+          "[Flight SQL] Must provide String " + PARAM_DRIVER + " parameter");

Review Comment:
   It is not specific to FlightSQL, correct?



##########
java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.arrow.adbc.driver.jni.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.util.Preconditions;
+
+public enum JniLoader {

Review Comment:
   (design) it's not a common pattern to use an enum class directly for 
creating a singleton, and not sure if there are benefits outside of it vs using 
a regular class.
   
   I'm not even sure `INSTANCE` is needed since things are delegated to 
`NativeAdbc` anyway. It looks to me that `NativeAdbc` could simply have a 
static initializer invoking some `JniLoader#checkInitialized()` for example 
which would cause the library to be loaded or `NativeAdbc` class loading to 
fail otherwise



##########
java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.arrow.adbc.driver.jni.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.util.Preconditions;
+
+public enum JniLoader {
+  INSTANCE;
+
+  JniLoader() {
+    final String libraryName = "adbc_driver_jni";
+    String libraryToLoad =
+        libraryName + "/" + getNormalizedArch() + "/" + 
System.mapLibraryName(libraryName);
+
+    try {
+      InputStream is = 
JniLoader.class.getClassLoader().getResourceAsStream(libraryToLoad);
+      if (is == null) {
+        throw new FileNotFoundException(libraryToLoad);
+      }
+      File temp =
+          File.createTempFile("adbc-jni-", ".tmp", new 
File(System.getProperty("java.io.tmpdir")));
+      temp.deleteOnExit();
+
+      try (is) {
+        Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
+      }
+      Runtime.getRuntime().load(temp.getAbsolutePath());
+    } catch (IOException e) {
+      throw new IllegalStateException("Error loading native library: " + e);
+    }
+  }
+
+  private String getNormalizedArch() {
+    String arch = System.getProperty("os.arch").toLowerCase(Locale.US);
+    switch (arch) {
+      case "amd64":
+        return "x86_64";
+      case "aarch64":
+        return "aarch_64";
+      default:
+        throw new RuntimeException("ADBC JNI driver not supported on 
architecture " + arch);
+    }
+  }
+
+  public NativeHandle openDatabase(Map<String, String> parameters) {
+    String[] nativeParameters = new String[parameters.size() * 2];
+    int index = 0;
+    for (Map.Entry<String, String> parameter : parameters.entrySet()) {
+      nativeParameters[index++] = parameter.getKey();
+      nativeParameters[index++] = parameter.getValue();
+    }
+    try {
+      return NativeAdbc.openDatabase(1001000, nativeParameters);
+    } catch (NativeAdbcException e) {
+      // TODO: convert to AdbcException
+      throw new RuntimeException(e);
+    }
+  }
+
+  public NativeHandle openConnection(NativeHandle database) {
+    Preconditions.checkArgument(database.getHandleType() == 
NativeHandleType.DATABASE);
+    try {
+      return NativeAdbc.openConnection(database.getHandle());
+    } catch (NativeAdbcException e) {
+      // TODO: convert to AdbcException
+      throw new RuntimeException(e);
+    }
+  }
+
+  public NativeHandle openStatement(NativeHandle connection) {
+    Preconditions.checkArgument(connection.getHandleType() == 
NativeHandleType.CONNECTION);
+    try {
+      return NativeAdbc.openStatement(connection.getHandle());
+    } catch (NativeAdbcException e) {
+      // TODO: convert to AdbcException
+      throw new RuntimeException(e);
+    }
+  }
+
+  public NativeQueryResult statementExecuteQuery(NativeHandle statement) 
throws AdbcException {

Review Comment:
   It says `AdbcException` is being thrown but not sure it's true in practice...



##########
java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/NativeQueryResult.java:
##########
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.arrow.adbc.driver.jni.impl;
+
+public class NativeQueryResult {
+  public final long rowsAffected;

Review Comment:
   (design) maybe we should model after Java records and still make those 
fields private and create accessors



##########
java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/NativeAdbcException.java:
##########
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.arrow.adbc.driver.jni.impl;
+
+/**
+ * Wrapper for a {@code struct AdbcException} that doesn't depend on other 
Java code.
+ *
+ * <p>This breaks a dependency chain in compilation. If we directly used 
AdbcException, then we
+ * would need to compile the Java code before compiling JNI code, but we need 
the compiled JNI code

Review Comment:
   this is surprising? I thought `javah` would use the source code, and that 
`javac` has no way to check native code? Is the circular dependency actually 
because of tests?



##########
java/driver/jni/src/main/java/org/apache/arrow/adbc/driver/jni/impl/JniLoader.java:
##########
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.arrow.adbc.driver.jni.impl;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.StandardCopyOption;
+import java.util.Locale;
+import java.util.Map;
+import org.apache.arrow.adbc.core.AdbcException;
+import org.apache.arrow.util.Preconditions;
+
+public enum JniLoader {
+  INSTANCE;
+
+  JniLoader() {
+    final String libraryName = "adbc_driver_jni";
+    String libraryToLoad =
+        libraryName + "/" + getNormalizedArch() + "/" + 
System.mapLibraryName(libraryName);
+
+    try {
+      InputStream is = 
JniLoader.class.getClassLoader().getResourceAsStream(libraryToLoad);
+      if (is == null) {
+        throw new FileNotFoundException(libraryToLoad);
+      }
+      File temp =
+          File.createTempFile("adbc-jni-", ".tmp", new 
File(System.getProperty("java.io.tmpdir")));
+      temp.deleteOnExit();
+
+      try (is) {
+        Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
+      }
+      Runtime.getRuntime().load(temp.getAbsolutePath());
+    } catch (IOException e) {
+      throw new IllegalStateException("Error loading native library: " + e);
+    }
+  }
+
+  private String getNormalizedArch() {
+    String arch = System.getProperty("os.arch").toLowerCase(Locale.US);
+    switch (arch) {
+      case "amd64":
+        return "x86_64";
+      case "aarch64":
+        return "aarch_64";
+      default:
+        throw new RuntimeException("ADBC JNI driver not supported on 
architecture " + arch);
+    }
+  }
+
+  public NativeHandle openDatabase(Map<String, String> parameters) {
+    String[] nativeParameters = new String[parameters.size() * 2];
+    int index = 0;
+    for (Map.Entry<String, String> parameter : parameters.entrySet()) {
+      nativeParameters[index++] = parameter.getKey();
+      nativeParameters[index++] = parameter.getValue();
+    }
+    try {
+      return NativeAdbc.openDatabase(1001000, nativeParameters);
+    } catch (NativeAdbcException e) {
+      // TODO: convert to AdbcException
+      throw new RuntimeException(e);
+    }
+  }
+
+  public NativeHandle openConnection(NativeHandle database) {
+    Preconditions.checkArgument(database.getHandleType() == 
NativeHandleType.DATABASE);

Review Comment:
   (design) can we avoid the generic handle and use some strong typing instead? 
For example by creating sub classes of `NativeHandle`?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to