001package org.hl7.fhir.r5.utils.sql; 002 003import java.sql.Connection; 004import java.sql.PreparedStatement; 005import java.sql.SQLType; 006import java.util.List; 007 008import org.hl7.fhir.exceptions.FHIRException; 009import org.hl7.fhir.r5.model.Base; 010import org.hl7.fhir.utilities.CommaSeparatedStringBuilder; 011 012public class StorageSqlite3 implements Storage { 013 014 public static class SQLiteStore extends Store { 015 private PreparedStatement p; 016 017 protected SQLiteStore(String name, PreparedStatement p) { 018 super(name); 019 this.p = p; 020 } 021 022 public PreparedStatement getP() { 023 return p; 024 } 025 026 } 027 028 private Connection conn; 029 private int nextKey = 0; 030 031 public StorageSqlite3(Connection conn) { 032 super(); 033 this.conn = conn; 034 } 035 036 @Override 037 public Store createStore(String name, List<Column> columns) { 038 try { 039 CommaSeparatedStringBuilder fields = new CommaSeparatedStringBuilder(", "); 040 CommaSeparatedStringBuilder values = new CommaSeparatedStringBuilder(", "); 041 StringBuilder b = new StringBuilder(); 042 b.append("Create Table "+name+" ( "); 043 b.append("ViewRowKey integer NOT NULL"); 044 for (Column column : columns) { 045 b.append(", "+column.getName()+" "+sqliteType(column.getKind())+" NULL"); // index columns are always nullable 046 fields.append(column.getName()); 047 values.append("?"); 048 } 049 b.append(", PRIMARY KEY (ViewRowKey))\r\n"); 050 conn.createStatement().execute(b.toString()); 051 052 String isql = "Insert into "+name+" (ViewRowKey, "+fields.toString()+") values (?, "+values.toString()+")"; 053 PreparedStatement psql = conn.prepareStatement(isql); 054 return new SQLiteStore(name, psql); 055 } catch (Exception e) { 056 throw new FHIRException(e); 057 } 058 } 059 060 private String sqliteType(ColumnKind type) { 061 switch (type) { 062 case DateTime: return "Text"; 063 case Decimal: return "Real"; 064 case Integer: return "Integer"; 065 case String: return "Text"; 066 case Time: return "Text"; 067 case Binary: return "Text"; 068 case Boolean: return "Integer"; 069 case Complex: throw new FHIRException("SQLite runner does not handle complexes"); 070 } 071 return null; 072 } 073 074 @Override 075 public void addRow(Store store, List<Cell> cells) { 076 try { 077 SQLiteStore sqls = (SQLiteStore) store; 078 PreparedStatement p = sqls.getP(); 079 p.setInt(1, ++nextKey); 080 for (int i = 0; i < cells.size(); i++) { 081 Cell c = cells.get(i); 082 switch (c.getColumn().getKind()) { 083 case Null: 084 p.setNull(i+2, java.sql.Types.NVARCHAR); 085 case Binary: 086 p.setBytes(i+2, c.getValues().size() == 0 ? null : c.getValues().get(0).getValueBinary()); 087 break; 088 case Boolean: 089 p.setBoolean(i+2, c.getValues().size() == 0 ? false : c.getValues().get(0).getValueBoolean().booleanValue()); 090 break; 091 case DateTime: 092 p.setDate(i+2, c.getValues().size() == 0 ? null : new java.sql.Date(c.getValues().get(0).getValueDate().getTime())); 093 break; 094 case Decimal: 095 p.setString(i+2, c.getValues().size() == 0 ? null : c.getValues().get(0).getValueString()); 096 break; 097 case Integer: 098 p.setInt(i+2, c.getValues().size() == 0 ? 0 : c.getValues().get(0).getValueInt().intValue()); 099 break; 100 case String: 101 p.setString(i+2, c.getValues().size() == 0 ? null : c.getValues().get(0).getValueString()); 102 break; 103 case Time: 104 p.setString(i+2, c.getValues().size() == 0 ? null : c.getValues().get(0).getValueString()); 105 break; 106 case Complex: throw new FHIRException("SQLite runner does not handle complexes"); 107 } 108 } 109 p.execute(); 110 } catch (Exception e) { 111 throw new FHIRException(e); 112 } 113 114 } 115 116 @Override 117 public void finish(Store store) { 118 // nothing 119 } 120 121 @Override 122 public boolean supportsArrays() { 123 return false; 124 } 125 126 @Override 127 public boolean supportsComplexTypes() { 128 return false; 129 } 130 131 @Override 132 public boolean needsName() { 133 return true; 134 } 135 136 @Override 137 public String getKeyForSourceResource(Base res) { 138 throw new Error("Key management for resources isn't decided yet"); 139 } 140 141 @Override 142 public String getKeyForTargetResource(Base res) { 143 throw new Error("Key management for resources isn't decided yet"); 144 } 145}