1 #include "Sql.h"
2
3 namespace Upp {
4
FlushColumn()5 void SqlSchema::FlushColumn() {
6 if(column.IsEmpty()) return;
7 for(int i = items ? 0 : Null; items ? i < items : IsNull(i); i++) {
8 String cn = Format("\t%-20s ", ~Expand("@c", i)) + CurrentType();
9 if(dialect == SQLITE3)
10 cn = Format(" %s ", ~Expand("@c", i)) + CurrentType();
11 String attr = Expand(attribute, i);
12 String cd = cn + attr;
13 if(firstcolumn) {
14 Schema() << Expand("create table @t (\n");
15 SchemaDrop() << Expand("drop table @t;\n");
16 if(dialect == SQLITE3)
17 Upgrade() << Expand("create table @t ( ") << cd << " )" << table_suffix << ";\n";
18 else
19 Upgrade() << Expand("create table @t (\n") << cd << "\n)" << table_suffix << ";\n\n";
20 }
21 else
22 {
23 if(dialect == MSSQL) {
24 Upgrade() << Expand("alter table @t add ") << cn << ";\n";
25 Upgrade() << Expand("alter table @t alter column ") << cd << ";\n";
26 }
27 else
28 if(dialect == MY_SQL) {
29 Upgrade() << Expand("alter table @t add ") << cn << ";\n";
30 Upgrade() << Expand("alter table @t modify ") << cd << ";\n";
31 }
32 else
33 if (dialect == SQLITE3 || dialect == MY_SQL)
34 Upgrade() << Expand("alter table @t add ") << cd << ";\n";
35 else
36 if (dialect == PGSQL)
37 Upgrade() << Expand("alter table @t add \n") << cd << "\n;\n\n";
38 else
39 Upgrade() << Expand("alter table @t add (\n") << cd << "\n);\n\n";
40 Schema() << ",\n";
41 }
42 Schema() << cd;
43 firstcolumn = false;
44 }
45 column.Clear();
46 }
47
FlushTable()48 void SqlSchema::FlushTable() {
49 FlushColumn();
50 if(!table.IsEmpty())
51 Schema() << "\n)" << table_suffix << ";\n\n";
52 table.Clear();
53 }
54
Object(const char * text,const char * drop)55 void SqlSchema::Object(const char *text, const char *drop) {
56 FlushTable();
57 Schema() << text << '\n';
58 SchemaDrop() << drop << '\n';
59 }
60
Upgrade(const char * text)61 void SqlSchema::Upgrade(const char *text) {
62 Upgrade() << text << '\n';
63 }
64
Table(const char * name)65 void SqlSchema::Table(const char *name) {
66 FlushTable();
67 table = name;
68 table_suffix = Null;
69 Attributes() << '\n';
70 AttributesDrop() << '\n';
71 firstcolumn = true;
72 }
73
TableSuffix(const char * suffix)74 void SqlSchema::TableSuffix(const char *suffix)
75 {
76 table_suffix << suffix;
77 }
78
Column(const char * _type,const char * name)79 void SqlSchema::Column(const char *_type, const char *name) {
80 FlushColumn();
81
82 items = 0;
83 type = _type;
84 column = prefix + name;
85 attribute.Clear();
86 }
87
SqlName(const char * name)88 void SqlSchema::SqlName(const char *name)
89 {
90 (firstcolumn ? table : column) = prefix + name;
91 }
92
ColumnArray(const char * type,const char * name,int _items)93 void SqlSchema::ColumnArray(const char *type, const char *name, int _items) {
94 Column(type, name);
95 items = _items;
96 }
97
Attribute(const char * attr,const char * drop)98 void SqlSchema::Attribute(const char *attr, const char *drop) {
99 for(int i = items ? 0 : Null; items ? i < items : IsNull(i); i++) {
100 Attributes() << Expand(attr, i) << '\n';
101 AttributesDrop() << Expand(drop, i) << '\n';
102 }
103 }
104
InlineAttribute(const char * attr)105 void SqlSchema::InlineAttribute(const char *attr) {
106 attribute << (*attr == ',' ? "" : " ") << Expand(attr);
107 }
108
Config(const char * config,const char * drop)109 void SqlSchema::Config(const char *config, const char *drop) {
110 Config() << config;
111 ConfigDrop() << drop;
112 }
113
CurrentTable() const114 String SqlSchema::CurrentTable() const
115 {
116 return IsNull(schemaname) ? table : schemaname + '.' + table;
117 }
118
Expand(const char * txt,int i) const119 String SqlSchema::Expand(const char *txt, int i) const
120 {
121 String n, r;
122 if(!IsNull(i))
123 n = Format("%d", i);
124 String c = CurrentColumn() + n;
125 String v = table + '$' + c;
126 v = v.Mid(max(0, min(v.GetLength(), v.GetLength() - maxidlen)));
127 while(*txt) {
128 if(*txt == '@' && txt[1]) {
129 switch(*++txt) {
130 case 'i': r.Cat(n); break;
131 case 't': r.Cat(CurrentTable()); break;
132 case 'u': r.Cat(table); break;
133 case 'c': r.Cat(c); break;
134 case 'C': r.Cat(CurrentColumn()); break;
135 case 'T': r.Cat(CurrentType()); break;
136 case 'x': r.Cat(v); break;
137 case 's': if(!IsNull(schemaname)) { r.Cat(schemaname); r.Cat('.'); } break;
138 default: r.Cat(*txt); break;
139 }
140 }
141 else
142 r.Cat(*txt);
143 txt++;
144 }
145 return r;
146 }
147
Var(void (* type)(SqlSchema & s),const char * name)148 void SqlSchema::Var(void (*type)(SqlSchema& s), const char *name) {
149 String p = prefix;
150 prefix << name << '$';
151 (*type)(*this);
152 prefix = p;
153 }
154
Script(int si)155 String& SqlSchema::Script(int si) { return script.At(si); }
Script(int si) const156 String SqlSchema::Script(int si) const { return si < script.GetCount() ? script[si] : String(); }
Schema()157 String& SqlSchema::Schema() { return Script(SCHEMA); }
SchemaDrop()158 String& SqlSchema::SchemaDrop() { return Script(DROPSCHEMA); }
Attributes()159 String& SqlSchema::Attributes() { return Script(ATTRIBUTES); }
AttributesDrop()160 String& SqlSchema::AttributesDrop() { return Script(DROPATTRIBUTES); }
Upgrade()161 String& SqlSchema::Upgrade() { return Script(UPGRADE); }
UpgradeDrop()162 String& SqlSchema::UpgradeDrop() { return Script(DROPUPGRADE); }
Config()163 String& SqlSchema::Config() { return Script(CONFIG); }
ConfigDrop()164 String& SqlSchema::ConfigDrop() { return Script(DROPCONFIG); }
165
NormalFileName(int i,const char * dir,const char * name) const166 String SqlSchema::NormalFileName(int i, const char *dir, const char *name) const {
167 ASSERT(i >= 0 && i <= DROPCONFIG);
168 String n;
169 if(name)
170 n = name;
171 else
172 #ifdef PLATFORM_WIN32
173 n = ForceExt(GetFileName(GetExeFilePath()), ".sql");
174 #endif
175 #ifdef PLATFORM_POSIX
176 n = "script.sql";
177 #endif
178 const char *pfx[] = {
179 "S_", "SD_", "A_", "AD_", "U_", "UD_", "C_", "CD_"
180 };
181 return dir ? AppendFileName(dir, pfx[i] + n) : ConfigFile(pfx[i] + n);
182 }
183
ScriptChanged(int i,const char * dir,const char * name) const184 bool SqlSchema::ScriptChanged(int i, const char *dir, const char *name) const {
185 String fn = NormalFileName(i, dir, name);
186 return LoadFile(fn) != Script(i);
187 }
188
UpdateNormalFile(int i,const char * dir,const char * name) const189 bool SqlSchema::UpdateNormalFile(int i, const char *dir, const char *name) const {
190 String fn = NormalFileName(i, dir, name);
191 if(LoadFile(fn) != Script(i)) {
192 DeleteFile(fn);
193 SaveFile(fn, Script(i));
194 return true;
195 }
196 return false;
197 }
198
SaveNormal(const char * dir,const char * name) const199 void SqlSchema::SaveNormal(const char *dir, const char *name) const {
200 for(int i = SCHEMA; i <= DROPCONFIG; i++)
201 UpdateNormalFile(i, dir, name);
202 }
203
SqlSchema(int dialect_)204 SqlSchema::SqlSchema(int dialect_)
205 {
206 dialect = dialect_;
207 maxidlen = 63;
208 if(dialect == MSSQL)
209 maxidlen = 128;
210 if(dialect == ORACLE)
211 maxidlen = 24;
212 }
213
operator *(SqlSchema & schema,const SqlInsert & insert)214 void operator*(SqlSchema& schema, const SqlInsert& insert) {
215 schema.Config() << SqlStatement(insert).Get(schema.GetDialect()) << ";\n";
216 schema.ConfigDrop() << SqlStatement(Delete(insert.GetTable())
217 .Where(insert.GetKeyColumn() == insert.GetKeyValue()))
218 .Get(schema.GetDialect())
219 << ";\n";
220 }
221
sSqlRename()222 VectorMap<String, String>& sSqlRename()
223 {
224 static VectorMap<String, String> x;
225 return x;
226 }
227
228 const char *RegSqlName__;
229
SqlRename__(const char * name)230 void SqlRename__(const char *name)
231 {
232 static auto& rename = sSqlRename();
233 if(RegSqlName__)
234 rename.Add(RegSqlName__, name);
235 RegSqlName__ = NULL;
236 }
237
SqlResolveId__(const char * id)238 const char *SqlResolveId__(const char *id)
239 {
240 static auto& rename = sSqlRename();
241 int q;
242 if(rename.GetCount() && (q = rename.Find(id)) >= 0)
243 return rename[q];
244 return id; // cannot be conditional expression as we are returning const char * !
245 }
246
247 };