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 };