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