@@ -58,6 +58,7 @@ public class DuckDBAppender implements AutoCloseable {
5858
5959 supportedTypes .add (DUCKDB_TYPE_STRUCT .typeId );
6060 supportedTypes .add (DUCKDB_TYPE_UNION .typeId );
61+ supportedTypes .add (DUCKDB_TYPE_ENUM .typeId );
6162 }
6263 private static final CAPIType [] int8Types = new CAPIType [] {DUCKDB_TYPE_TINYINT , DUCKDB_TYPE_UTINYINT };
6364 private static final CAPIType [] int16Types = new CAPIType [] {DUCKDB_TYPE_SMALLINT , DUCKDB_TYPE_USMALLINT };
@@ -69,6 +70,8 @@ public class DuckDBAppender implements AutoCloseable {
6970 private static final CAPIType [] timestampMicrosTypes =
7071 new CAPIType [] {DUCKDB_TYPE_TIMESTAMP , DUCKDB_TYPE_TIMESTAMP_TZ };
7172 private static final CAPIType [] collectionTypes = new CAPIType [] {DUCKDB_TYPE_ARRAY , DUCKDB_TYPE_LIST };
73+ private static final CAPIType [] varlenTypes = new CAPIType [] {DUCKDB_TYPE_VARCHAR , DUCKDB_TYPE_BLOB };
74+ private static final CAPIType [] varcharOrEnumTypes = new CAPIType [] {DUCKDB_TYPE_VARCHAR , DUCKDB_TYPE_ENUM };
7275
7376 private static final int STRING_MAX_INLINE_BYTES = 12 ;
7477
@@ -564,7 +567,7 @@ public DuckDBAppender appendByteArray(byte[][] values, boolean[][] nullMask) thr
564567 }
565568
566569 public DuckDBAppender append (byte [] values ) throws SQLException {
567- Column col = currentColumn (DUCKDB_TYPE_BLOB );
570+ Column col = currentColumn (varlenTypes );
568571 if (values == null ) {
569572 return appendNull ();
570573 }
@@ -740,13 +743,24 @@ public DuckDBAppender append(double[][] values, boolean[][] nullMask) throws SQL
740743 // append objects
741744
742745 public DuckDBAppender append (String value ) throws SQLException {
743- Column col = currentColumn (DUCKDB_TYPE_VARCHAR );
746+ Column col = currentColumn (varcharOrEnumTypes );
744747 if (value == null ) {
745748 return appendNull ();
746749 }
747750
748- byte [] bytes = value .getBytes (UTF_8 );
749- putStringOrBlob (col , rowIdx , bytes );
751+ switch (col .colType ) {
752+ case DUCKDB_TYPE_VARCHAR : {
753+ byte [] bytes = value .getBytes (UTF_8 );
754+ putStringOrBlob (col , rowIdx , bytes );
755+ break ;
756+ }
757+ case DUCKDB_TYPE_ENUM : {
758+ putEnum (col , rowIdx , value );
759+ break ;
760+ }
761+ default :
762+ throw new SQLException (createErrMsg ("Invalid type: " + col .colType ));
763+ }
750764
751765 moveToNextColumn ();
752766 return this ;
@@ -1842,6 +1856,16 @@ private void putCompositeElement(Column col, long vectorIdx, Object value) throw
18421856 putStringOrBlob (col , vectorIdx , bytes );
18431857 break ;
18441858 }
1859+ case DUCKDB_TYPE_ENUM : {
1860+ String st = (String ) value ;
1861+ putEnum (col , vectorIdx , st );
1862+ break ;
1863+ }
1864+ case DUCKDB_TYPE_BLOB : {
1865+ byte [] bytes = (byte []) (value );
1866+ putStringOrBlob (col , vectorIdx , bytes );
1867+ break ;
1868+ }
18451869 case DUCKDB_TYPE_UUID : {
18461870 UUID uid = (UUID ) value ;
18471871 long mostSigBits = uid .getMostSignificantBits ();
@@ -2058,6 +2082,31 @@ private Column putUnionTag(Column col, long vectorIdx, String tag) throws SQLExc
20582082 return col .children .get (fieldWithTag );
20592083 }
20602084
2085+ private void putEnum (Column col , long vectorIdx , String value ) throws SQLException {
2086+ Integer numValueNullable = col .enumDict .get (value );
2087+ if (null == numValueNullable ) {
2088+ throw new SQLException (createErrMsg ("invalid ENUM value specified: '" + value +
2089+ "', expected one of: " + col .enumDict .keySet ()));
2090+ }
2091+
2092+ int pos = (int ) (vectorIdx * col .enumInternalType .widthBytes );
2093+ col .data .position (pos );
2094+
2095+ switch (col .enumInternalType ) {
2096+ case DUCKDB_TYPE_UTINYINT :
2097+ col .data .put (numValueNullable .byteValue ());
2098+ return ;
2099+ case DUCKDB_TYPE_USMALLINT :
2100+ col .data .putShort (numValueNullable .shortValue ());
2101+ return ;
2102+ case DUCKDB_TYPE_UINTEGER :
2103+ col .data .putInt (numValueNullable .intValue ());
2104+ return ;
2105+ default :
2106+ throw new SQLException (createErrMsg ("invalid ENUM internal type: " + col .enumInternalType ));
2107+ }
2108+ }
2109+
20612110 // state invariants
20622111
20632112 private boolean rowBegunInvariant () {
@@ -2254,6 +2303,17 @@ private static List<Column> createTopLevelColumns(ByteBuffer chunkRef, ByteBuffe
22542303 return columns ;
22552304 }
22562305
2306+ private static Map <String , Integer > readEnumDict (ByteBuffer colTypeRef ) {
2307+ Map <String , Integer > dict = new LinkedHashMap <>();
2308+ long size = duckdb_enum_dictionary_size (colTypeRef );
2309+ for (long i = 0 ; i < size ; i ++) {
2310+ byte [] nameUtf8 = duckdb_enum_dictionary_value (colTypeRef , i );
2311+ String name = strFromUTF8 (nameUtf8 );
2312+ dict .put (name , (int ) i );
2313+ }
2314+ return dict ;
2315+ }
2316+
22572317 private static class Column {
22582318 private final Column parent ;
22592319 private final int idx ;
@@ -2264,6 +2324,8 @@ private static class Column {
22642324 private final int decimalScale ;
22652325 private final long arraySize ;
22662326 private final String structFieldName ;
2327+ private final Map <String , Integer > enumDict ;
2328+ private final CAPIType enumInternalType ;
22672329
22682330 private final ByteBuffer vectorRef ;
22692331 private final List <Column > children = new ArrayList <>();
@@ -2323,8 +2385,17 @@ private Column(Column parent, int idx, ByteBuffer colTypeRef, ByteBuffer vector,
23232385 this .arraySize = duckdb_array_type_array_size (parent .colTypeRef );
23242386 }
23252387
2388+ if (colType == DUCKDB_TYPE_ENUM ) {
2389+ this .enumDict = readEnumDict (this .colTypeRef );
2390+ int enumInternalTypeId = duckdb_enum_internal_type (this .colTypeRef );
2391+ this .enumInternalType = capiTypeFromTypeId (enumInternalTypeId );
2392+ } else {
2393+ this .enumDict = null ;
2394+ this .enumInternalType = null ;
2395+ }
2396+
23262397 long maxElems = maxElementsCount ();
2327- if (colType .widthBytes > 0 || colType == DUCKDB_TYPE_DECIMAL ) {
2398+ if (colType .widthBytes > 0 || colType == DUCKDB_TYPE_DECIMAL || colType == DUCKDB_TYPE_ENUM ) {
23282399 long vectorSizeBytes = maxElems * widthBytes ();
23292400 this .data = duckdb_vector_get_data (vectorRef , vectorSizeBytes );
23302401 if (null == this .data ) {
@@ -2423,6 +2494,8 @@ void setNullOnVectorIdx(long vectorIdx) {
24232494 long widthBytes () {
24242495 if (colType == DUCKDB_TYPE_DECIMAL ) {
24252496 return decimalInternalType .widthBytes ;
2497+ } else if (colType == DUCKDB_TYPE_ENUM ) {
2498+ return enumInternalType .widthBytes ;
24262499 } else {
24272500 return colType .widthBytes ;
24282501 }
0 commit comments