35
43
44:-module(cql_autoschema,
45 []). 46
84
85:-use_module(library(cql/cql_database)). 86:-use_module(library(dcg/basics)). 87
90
91schema_fact(Schema, DBMS, dbms(Schema, DBMS)).
92
93schema_fact(Schema, 'PostgreSQL', Fact):-
94 odbc_connection_call(Schema, Connection, odbc_query(Connection, 'SELECT table_name, column_name, data_type, character_maximum_length, numeric_precision, numeric_scale, domain_name, is_nullable, column_default FROM INFORMATION_SCHEMA.columns WHERE table_schema = \'public\'', row(EntityName, ColumnName, NativeType, CharacterMaximumLength, NumericPrecision, NumericScale, DomainType, IsNullable, ColumnDefault))),
95 ( IsNullable == '1' -> AllowsNulls = allows_nulls(true) ; AllowsNulls = allows_nulls(false) ),
96 map_native_type(NativeType, CharacterMaximumLength, NumericPrecision, NumericScale, Mapped),
97 ( DomainType \== {null} -> DomainOrNativeType = domain(DomainType) ; DomainOrNativeType = native_type(Mapped) ),
98 IsIdentity = is_identity(false),
99 ( Fact = database_attribute(table, Schema, EntityName, ColumnName, DomainOrNativeType, AllowsNulls, IsIdentity, ColumnDefault)
100 ; Fact = odbc_data_type(Schema, EntityName, ColumnName, Mapped)
101 ).
102
103schema_fact(Schema, 'PostgreSQL', primary_key_column_name(Schema, EntityName, ColumnName)):-
104 odbc_connection_call(Schema, Connection, odbc_query(Connection, 'SELECT kcu.table_name, column_name FROM INFORMATION_SCHEMA.key_column_usage KCU INNER JOIN INFORMATION_SCHEMA.table_constraints tc ON(tc.table_name = kcu.table_name AND tc.constraint_type = \'PRIMARY KEY\') WHERE kcu.table_schema = \'public\'', row(EntityName, ColumnName))).
105
106schema_fact(Schema, 'PostgreSQL', database_domain(DomainName, Mapped)):-
107 odbc_connection_call(Schema, Connection, odbc_query(Connection, 'SELECT domain_name, data_type, character_maximum_length, numeric_precision, numeric_scale FROM INFORMATION_SCHEMA.domains WHERE domain_schema = \'public\'', row(DomainName, NativeType, CharacterMaximumLength, NumericPrecision, NumericScale))),
108 map_native_type(NativeType, CharacterMaximumLength, NumericPrecision, NumericScale, Mapped).
109
110schema_fact(Schema, 'PostgreSQL', routine_return_type(Schema, RoutineName, Mapped)):-
111 odbc_connection_call(Schema, Connection, odbc_query(Connection, 'SELECT data_type, character_maximum_length, numeric_precision, numeric_scale FROM INFORMATION_SCHEMA.routines WHERE routine_schema = \'public\'', row(RoutineName, NativeType, CharacterMaximumLength, NumericPrecision, NumericScale))),
112 map_native_type(NativeType, CharacterMaximumLength, NumericPrecision, NumericScale, Mapped).
113
114schema_fact(Schema, 'SQLite', Fact):-
115 findall(EntityName,
116 odbc_connection_call(Schema, Connection, odbc_query(Connection, 'SELECT name FROM sqlite_master WHERE type = \'table\'', row(EntityName))),
117 EntityNames),
118 member(EntityName, EntityNames),
119 format(atom(Pragma), 'PRAGMA table_info(~w)', [EntityName]),
120 odbc_connection_call(Schema, Connection, odbc_query(Connection, Pragma, Row)),
121 Row = row(_CID, ColumnName, ColumnTypeAtom, NotNullable, ColumnDefault, IsPkMember),
122 ( NotNullable == 0 ->
123 AllowsNulls = allows_nulls(true)
124 ; otherwise->
125 AllowsNulls = allows_nulls(false)
126 ),
127 ColumnTypeAtom \== '', 128 ( sqlite_type(ColumnTypeAtom, ColumnType)->
129 true
130 ; otherwise->
131 writeln(bad_type(EntityName, ColumnName, ColumnTypeAtom))
132 ),
133 IsIdentity = is_identity(false), 134 135 ( ColumnType == datetime ->
136 137 OdbcDataType = timestamp
138 ; otherwise->
139 OdbcDataType = ColumnType
140 ),
141 ( Fact = database_attribute(table, Schema, EntityName, ColumnName, native_type(ColumnType), AllowsNulls, IsIdentity, ColumnDefault)
142 ; Fact = odbc_data_type(Schema, EntityName, ColumnName, OdbcDataType)
143 ; IsPkMember == 1, Fact = primary_key_column_name(Schema, EntityName, ColumnName)
144 ).
145
146
147map_native_type('character varying', N, _, _, varchar(N)):- !.
148map_native_type('decimal', _, P, S, decimal(P, S)):- !.
149map_native_type(X, _, _, _, X).
150
151sqlite_type(Atom, Type):-
152 atom_codes(Atom, Codes),
153 sqlite_type_1(Type, Codes, []).
154sqlite_type_1(decimal(P, S))-->
155 ( "DECIMAL" ; "decimal" ; "Decimal"),
156 !,
157 whitespace, "(", whitespace, number(P), whitespace, ",", whitespace, number(S), whitespace, ")".
158
159sqlite_type_1(varchar(N))-->
160 ( "VARCHAR" ; "varchar" ; "Varchar"),
161 !,
162 whitespace, "(", whitespace, number(N), whitespace, ")".
163
164sqlite_type_1(varbinary(max))-->
165 ( "VARBINARY" ; "varbinary" ; "Varbinary"), !.
166
167sqlite_type_1(longvarchar)-->
168 ( "LONGVARCHAR" ; "longvarchar" ; "Longvarchar"), !.
169
170sqlite_type_1(integer)-->
171 ( "INTEGER" ; "integer" ; "Integer"), !.
172
173sqlite_type_1(datetime)-->
174 ( "DATETIME" ; "datetime" ; "Datetime"), !.
175
176sqlite_type_1(bigint)-->
177 ( "BIGINT" ; "bigint" ; "Bigint"), !.
178
179sqlite_type_1(smallint)-->
180 ( "SMALLINT" ; "smallint" ; "Smallint"), !.
181
182
183whitespace--> [C], {code_type(C, white)}, !, whitespace.
184whitespace--> [].
185
186
187user:term_expansion(:-build_schema(Schema), Facts):-
188 odbc_connection_call(Schema, Connection, odbc_get_connection(Connection, dbms_name(DBMS))),
189 setof(cql:Fact,
190 schema_fact(Schema, DBMS, Fact),
191 Facts)