1*5696Snw141292 /*
2*5696Snw141292  * CDDL HEADER START
3*5696Snw141292  *
4*5696Snw141292  * The contents of this file are subject to the terms of the
5*5696Snw141292  * Common Development and Distribution License (the "License").
6*5696Snw141292  * You may not use this file except in compliance with the License.
7*5696Snw141292  *
8*5696Snw141292  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*5696Snw141292  * or http://www.opensolaris.org/os/licensing.
10*5696Snw141292  * See the License for the specific language governing permissions
11*5696Snw141292  * and limitations under the License.
12*5696Snw141292  *
13*5696Snw141292  * When distributing Covered Code, include this CDDL HEADER in each
14*5696Snw141292  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*5696Snw141292  * If applicable, add the following below this CDDL HEADER, with the
16*5696Snw141292  * fields enclosed by brackets "[]" replaced with your own identifying
17*5696Snw141292  * information: Portions Copyright [yyyy] [name of copyright owner]
18*5696Snw141292  *
19*5696Snw141292  * CDDL HEADER END
20*5696Snw141292  */
21*5696Snw141292 /*
22*5696Snw141292  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
23*5696Snw141292  * Use is subject to license terms.
24*5696Snw141292  */
25*5696Snw141292 
26*5696Snw141292 #ifndef _SCHEMA_H
27*5696Snw141292 #define	_SCHEMA_H
28*5696Snw141292 
29*5696Snw141292 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30*5696Snw141292 
31*5696Snw141292 #ifdef __cplusplus
32*5696Snw141292 extern "C" {
33*5696Snw141292 #endif
34*5696Snw141292 
35*5696Snw141292 /*
36*5696Snw141292  * Various macros (constant strings) containing:
37*5696Snw141292  *
38*5696Snw141292  *  - CREATE TABLE/INDEX/TRIGGER/VIEW SQL
39*5696Snw141292  *  - old versions of schema items that have changed
40*5696Snw141292  *  - SQL to detect the version currently installed in a db
41*5696Snw141292  *  - SQL to upgrade the schema from any older version to the current
42*5696Snw141292  *     - the SQL to install the current version of the schema on a
43*5696Snw141292  *       freshly created db is the SQL used to "upgrade" from "version 0"
44*5696Snw141292  *
45*5696Snw141292  * There is one set of such macros for the cache DB (CACHE_*) and
46*5696Snw141292  * another set for the persistent DB (DB_*).  The macros ending in _SQL
47*5696Snw141292  * are used in arguments to init_db_instance().
48*5696Snw141292  *
49*5696Snw141292  * Schema version detection SQL has the following form:
50*5696Snw141292  *
51*5696Snw141292  * SELECT CASE (SELECT count(*) FROM sqlite_master) WHEN 0 THEN 0 ELSE
52*5696Snw141292  * (CASE (SELECT count(*) FROM sqlite_master WHERE sql = <original schema> ...)
53*5696Snw141292  * WHEN <correct count> THEN 1 ELSE (CASE (<v2 schema>) WHEN ... THEN 2
54*5696Snw141292  * ELSE -1 END) END AS version;
55*5696Snw141292  *
56*5696Snw141292  * That is, check that there is no schema else that the current schema
57*5696Snw141292  * sql matches the original schema, else the next version, ... and
58*5696Snw141292  * return an integer identifying the schema.  Version numbers returned:
59*5696Snw141292  *
60*5696Snw141292  * -1 -> unknown schema  (shouldn't happen)
61*5696Snw141292  *  0 -> no schema       (brand new DB, install latest schema)
62*5696Snw141292  *  1 -> original schema (if != latest, then upgrade)
63*5696Snw141292  *  . -> ...             (if != latest, then upgrade)
64*5696Snw141292  *  n -> latest schema   (nothing to do)
65*5696Snw141292  *
66*5696Snw141292  * Upgrade SQL for the cache DB is simple: drop everything, create
67*5696Snw141292  * latest schema.  This means losing ephemeral mappings, so idmapd must
68*5696Snw141292  * tell the kernel about that in its registration call.
69*5696Snw141292  *
70*5696Snw141292  * Upgrade SQL for the persistent DB is simple: drop the indexes, create
71*5696Snw141292  * temporary tables with the latest schema, insert into those from the
72*5696Snw141292  * old tables (transforming the data in the process), then drop the old
73*5696Snw141292  * tables, create the latest schema, restore the data from the temp.
74*5696Snw141292  * tables and drop the temp tables.
75*5696Snw141292  *
76*5696Snw141292  * Complex, but it avoids all sorts of packaging install/upgrade
77*5696Snw141292  * complexity, requiring reboots on patch.
78*5696Snw141292  *
79*5696Snw141292  * Conventions:
80*5696Snw141292  * - each TABLE/INDEX gets its own macro, and the SQL therein must not
81*5696Snw141292  *   end in a semi-colon (';)
82*5696Snw141292  * - macros are named * TABLE_* for tables, INDEX_* for indexes,
83*5696Snw141292  *   *_VERSION_SQL for SQL for determining version number,
84*5696Snw141292  *   *_UPGRADE_FROM_v<version>_SQL for SQL for upgrading from some
85*5696Snw141292  *   schema, *_LATEST_SQL for SQL for installing the latest schema.
86*5696Snw141292  * - some macros nest expansions of other macros
87*5696Snw141292  *
88*5696Snw141292  * The latest schema has two columns for Windows user/group name in
89*5696Snw141292  * tables where there used to be one.  One of those columns contains the
90*5696Snw141292  * name as it came from the user or from AD, the other is set via a
91*5696Snw141292  * TRIGGER to be the lower-case version of the first, and we always
92*5696Snw141292  * search (and index) by the latter.  This is for case-insensitivity.
93*5696Snw141292  */
94*5696Snw141292 #define	TABLE_IDMAP_CACHE_v1 \
95*5696Snw141292 	"CREATE TABLE idmap_cache (" \
96*5696Snw141292 	"	sidprefix TEXT," \
97*5696Snw141292 	"	rid INTEGER," \
98*5696Snw141292 	"	windomain TEXT," \
99*5696Snw141292 	"	winname TEXT," \
100*5696Snw141292 	"	pid INTEGER," \
101*5696Snw141292 	"	unixname TEXT," \
102*5696Snw141292 	"	is_user INTEGER," \
103*5696Snw141292 	"	w2u INTEGER," \
104*5696Snw141292 	"	u2w INTEGER," \
105*5696Snw141292 	"	expiration INTEGER" \
106*5696Snw141292 	")"
107*5696Snw141292 
108*5696Snw141292 #define	TABLE_IDMAP_CACHE \
109*5696Snw141292 	"CREATE TABLE idmap_cache " \
110*5696Snw141292 	"(" \
111*5696Snw141292 	"	sidprefix TEXT," \
112*5696Snw141292 	"	rid INTEGER," \
113*5696Snw141292 	"	windomain TEXT," \
114*5696Snw141292 	"	canon_winname TEXT," \
115*5696Snw141292 	"	winname TEXT," \
116*5696Snw141292 	"	pid INTEGER," \
117*5696Snw141292 	"	unixname TEXT," \
118*5696Snw141292 	"	is_user INTEGER," \
119*5696Snw141292 	"	is_wuser INTEGER," \
120*5696Snw141292 	"	w2u INTEGER," \
121*5696Snw141292 	"	u2w INTEGER," \
122*5696Snw141292 	"	expiration INTEGER" \
123*5696Snw141292 	")"
124*5696Snw141292 
125*5696Snw141292 #define	INDEX_IDMAP_CACHE_SID_W2U_v1 \
126*5696Snw141292 	"CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache" \
127*5696Snw141292 	"		(sidprefix, rid, w2u)"
128*5696Snw141292 
129*5696Snw141292 #define	INDEX_IDMAP_CACHE_SID_W2U \
130*5696Snw141292 	"CREATE UNIQUE INDEX idmap_cache_sid_w2u ON idmap_cache" \
131*5696Snw141292 	"		(sidprefix, rid, is_user, w2u)"
132*5696Snw141292 
133*5696Snw141292 #define	INDEX_IDMAP_CACHE_PID_U2W \
134*5696Snw141292 	"CREATE UNIQUE INDEX idmap_cache_pid_u2w ON idmap_cache" \
135*5696Snw141292 	"		(pid, is_user, u2w)"
136*5696Snw141292 
137*5696Snw141292 #define	TRIGGER_IDMAP_CACHE_TOLOWER_INSERT \
138*5696Snw141292 	"CREATE TRIGGER idmap_cache_tolower_name_insert " \
139*5696Snw141292 	"AFTER INSERT ON idmap_cache " \
140*5696Snw141292 	"BEGIN " \
141*5696Snw141292 	"	UPDATE idmap_cache SET winname = lower_utf8(canon_winname)" \
142*5696Snw141292 	"		WHERE rowid = new.rowid;" \
143*5696Snw141292 	"END"
144*5696Snw141292 
145*5696Snw141292 #define	TRIGGER_IDMAP_CACHE_TOLOWER_UPDATE \
146*5696Snw141292 	"CREATE TRIGGER idmap_cache_tolower_name_update " \
147*5696Snw141292 	"AFTER UPDATE ON idmap_cache " \
148*5696Snw141292 	"BEGIN " \
149*5696Snw141292 	"	UPDATE idmap_cache SET winname = lower_utf8(canon_winname)" \
150*5696Snw141292 	"		WHERE rowid = new.rowid;" \
151*5696Snw141292 	"END"
152*5696Snw141292 
153*5696Snw141292 #define	TABLE_NAME_CACHE \
154*5696Snw141292 	"CREATE TABLE name_cache (" \
155*5696Snw141292 	"	sidprefix TEXT," \
156*5696Snw141292 	"	rid INTEGER," \
157*5696Snw141292 	"	name TEXT," \
158*5696Snw141292 	"	canon_name TEXT," \
159*5696Snw141292 	"	domain TEXT," \
160*5696Snw141292 	"	type INTEGER," \
161*5696Snw141292 	"	expiration INTEGER" \
162*5696Snw141292 	")"
163*5696Snw141292 
164*5696Snw141292 #define	TABLE_NAME_CACHE_v1 \
165*5696Snw141292 	"CREATE TABLE name_cache (" \
166*5696Snw141292 	"	sidprefix TEXT," \
167*5696Snw141292 	"	rid INTEGER," \
168*5696Snw141292 	"	name TEXT," \
169*5696Snw141292 	"	domain TEXT," \
170*5696Snw141292 	"	type INTEGER," \
171*5696Snw141292 	"	expiration INTEGER" \
172*5696Snw141292 	")"
173*5696Snw141292 
174*5696Snw141292 #define	TRIGGER_NAME_CACHE_TOLOWER_INSERT \
175*5696Snw141292 	"CREATE TRIGGER name_cache_tolower_name_insert " \
176*5696Snw141292 	"AFTER INSERT ON name_cache " \
177*5696Snw141292 	"BEGIN " \
178*5696Snw141292 	"	UPDATE name_cache SET name = lower_utf8(canon_name)" \
179*5696Snw141292 	"		WHERE rowid = new.rowid;" \
180*5696Snw141292 	"END"
181*5696Snw141292 
182*5696Snw141292 #define	TRIGGER_NAME_CACHE_TOLOWER_UPDATE \
183*5696Snw141292 	"CREATE TRIGGER name_cache_tolower_name_update " \
184*5696Snw141292 	"AFTER UPDATE ON name_cache " \
185*5696Snw141292 	"BEGIN " \
186*5696Snw141292 	"	UPDATE name_cache SET name = lower_utf8(canon_name)" \
187*5696Snw141292 	"		WHERE rowid = new.rowid;" \
188*5696Snw141292 	"END"
189*5696Snw141292 
190*5696Snw141292 #define	INDEX_NAME_CACHE_SID \
191*5696Snw141292 	"CREATE UNIQUE INDEX name_cache_sid ON name_cache" \
192*5696Snw141292 	"		(sidprefix, rid)"
193*5696Snw141292 
194*5696Snw141292 #define	INDEX_NAME_CACHE_NAME \
195*5696Snw141292 	"CREATE UNIQUE INDEX name_cache_name ON name_cache" \
196*5696Snw141292 	"		(name, domain)"
197*5696Snw141292 
198*5696Snw141292 #define	CACHE_INSTALL_SQL \
199*5696Snw141292 	TABLE_IDMAP_CACHE ";" \
200*5696Snw141292 	INDEX_IDMAP_CACHE_SID_W2U ";" \
201*5696Snw141292 	INDEX_IDMAP_CACHE_PID_U2W ";" \
202*5696Snw141292 	TRIGGER_IDMAP_CACHE_TOLOWER_INSERT ";" \
203*5696Snw141292 	TRIGGER_IDMAP_CACHE_TOLOWER_UPDATE ";" \
204*5696Snw141292 	TABLE_NAME_CACHE ";" \
205*5696Snw141292 	INDEX_NAME_CACHE_SID ";" \
206*5696Snw141292 	INDEX_NAME_CACHE_NAME ";" \
207*5696Snw141292 	TRIGGER_NAME_CACHE_TOLOWER_INSERT ";" \
208*5696Snw141292 	TRIGGER_NAME_CACHE_TOLOWER_UPDATE ";"
209*5696Snw141292 
210*5696Snw141292 #define	CACHE_VERSION_SQL \
211*5696Snw141292 	"SELECT CASE (SELECT count(*) FROM sqlite_master) WHEN 0 THEN 0 ELSE " \
212*5696Snw141292 	"(CASE (SELECT count(*) FROM sqlite_master WHERE " \
213*5696Snw141292 	"sql = '" TABLE_IDMAP_CACHE_v1 "' OR " \
214*5696Snw141292 	"sql = '" INDEX_IDMAP_CACHE_SID_W2U_v1 "' OR " \
215*5696Snw141292 	"sql = '" INDEX_IDMAP_CACHE_PID_U2W "' OR " \
216*5696Snw141292 	"sql = '" TABLE_NAME_CACHE_v1 "' OR " \
217*5696Snw141292 	"sql = '" INDEX_NAME_CACHE_SID "') " \
218*5696Snw141292 	"WHEN 5 THEN 1 ELSE " \
219*5696Snw141292 	"(CASE (SELECT count(*) FROM sqlite_master WHERE " \
220*5696Snw141292 	"sql = '" TABLE_IDMAP_CACHE"' OR " \
221*5696Snw141292 	"sql = '" INDEX_IDMAP_CACHE_SID_W2U "' OR " \
222*5696Snw141292 	"sql = '" INDEX_IDMAP_CACHE_PID_U2W "' OR " \
223*5696Snw141292 	"sql = '" TRIGGER_IDMAP_CACHE_TOLOWER_INSERT "' OR " \
224*5696Snw141292 	"sql = '" TRIGGER_IDMAP_CACHE_TOLOWER_UPDATE "' OR " \
225*5696Snw141292 	"sql = '" TABLE_NAME_CACHE "' OR " \
226*5696Snw141292 	"sql = '" INDEX_NAME_CACHE_SID "' OR " \
227*5696Snw141292 	"sql = '" INDEX_NAME_CACHE_NAME "' OR " \
228*5696Snw141292 	"sql = '" TRIGGER_NAME_CACHE_TOLOWER_INSERT "' OR " \
229*5696Snw141292 	"sql = '" TRIGGER_NAME_CACHE_TOLOWER_UPDATE "') " \
230*5696Snw141292 	"WHEN 10 THEN 2 ELSE -1 END) END) END AS version;"
231*5696Snw141292 
232*5696Snw141292 #define	CACHE_UPGRADE_FROM_v1_SQL \
233*5696Snw141292 	"DROP TABLE idmap_cache;" \
234*5696Snw141292 	"DROP TABLE name_cache;" \
235*5696Snw141292 	CACHE_INSTALL_SQL
236*5696Snw141292 
237*5696Snw141292 #define	CACHE_VERSION	2
238*5696Snw141292 
239*5696Snw141292 
240*5696Snw141292 #define	TABLE_NAMERULES_v1 \
241*5696Snw141292 	"CREATE TABLE namerules (" \
242*5696Snw141292 	"	is_user INTEGER NOT NULL," \
243*5696Snw141292 	"	windomain TEXT," \
244*5696Snw141292 	"	winname TEXT NOT NULL," \
245*5696Snw141292 	"	is_nt4 INTEGER NOT NULL," \
246*5696Snw141292 	"	unixname NOT NULL," \
247*5696Snw141292 	"	w2u_order INTEGER," \
248*5696Snw141292 	"	u2w_order INTEGER" \
249*5696Snw141292 	")"
250*5696Snw141292 
251*5696Snw141292 #define	TABLE_NAMERULES_BODY \
252*5696Snw141292 	"(" \
253*5696Snw141292 	"	is_user INTEGER NOT NULL," \
254*5696Snw141292 	"	is_wuser INTEGER NOT NULL," \
255*5696Snw141292 	"	windomain TEXT," \
256*5696Snw141292 	"	winname_display TEXT NOT NULL," \
257*5696Snw141292 	"	winname TEXT," \
258*5696Snw141292 	"	is_nt4 INTEGER NOT NULL," \
259*5696Snw141292 	"	unixname NOT NULL," \
260*5696Snw141292 	"	w2u_order INTEGER," \
261*5696Snw141292 	"	u2w_order INTEGER" \
262*5696Snw141292 	")"
263*5696Snw141292 
264*5696Snw141292 #define	TABLE_NAMERULES \
265*5696Snw141292 	"CREATE TABLE namerules " \
266*5696Snw141292 	TABLE_NAMERULES_BODY
267*5696Snw141292 
268*5696Snw141292 #define	INDEX_NAMERULES_W2U_v1 \
269*5696Snw141292 	"CREATE UNIQUE INDEX namerules_w2u ON namerules" \
270*5696Snw141292 	"		(winname, windomain, is_user, w2u_order)"
271*5696Snw141292 
272*5696Snw141292 #define	INDEX_NAMERULES_W2U \
273*5696Snw141292 	"CREATE UNIQUE INDEX namerules_w2u ON namerules" \
274*5696Snw141292 	"		(winname, windomain, is_user, is_wuser, w2u_order)"
275*5696Snw141292 
276*5696Snw141292 #define	INDEX_NAMERULES_U2W \
277*5696Snw141292 	"CREATE UNIQUE INDEX namerules_u2w ON namerules" \
278*5696Snw141292 	"		(unixname, is_user, u2w_order)"
279*5696Snw141292 
280*5696Snw141292 #define	TRIGGER_NAMERULES_TOLOWER_BODY \
281*5696Snw141292 	"BEGIN " \
282*5696Snw141292 	"	UPDATE namerules SET winname = lower_utf8(winname_display)" \
283*5696Snw141292 	"		WHERE rowid = new.rowid;" \
284*5696Snw141292 	"END"
285*5696Snw141292 
286*5696Snw141292 #define	TRIGGER_NAMERULES_TOLOWER_INSERT \
287*5696Snw141292 	"CREATE TRIGGER namerules_tolower_name_insert " \
288*5696Snw141292 	"AFTER INSERT ON namerules " \
289*5696Snw141292 	TRIGGER_NAMERULES_TOLOWER_BODY
290*5696Snw141292 
291*5696Snw141292 #define	TRIGGER_NAMERULES_TOLOWER_UPDATE \
292*5696Snw141292 	"CREATE TRIGGER namerules_tolower_name_update " \
293*5696Snw141292 	"AFTER UPDATE ON namerules " \
294*5696Snw141292 	TRIGGER_NAMERULES_TOLOWER_BODY
295*5696Snw141292 
296*5696Snw141292 #define	TRIGGER_NAMERULES_UNIQUE_BODY \
297*5696Snw141292 	"	SELECT CASE (SELECT count(*) FROM namerules AS n" \
298*5696Snw141292 	"		WHERE n.unixname = NEW.unixname AND" \
299*5696Snw141292 	"		n.is_user = NEW.is_user AND" \
300*5696Snw141292 	"		(n.winname != lower(NEW.winname_display) OR" \
301*5696Snw141292 	"		n.windomain != NEW.windomain ) AND" \
302*5696Snw141292 	"		n.u2w_order = NEW.u2w_order AND" \
303*5696Snw141292 	"		n.is_wuser != NEW.is_wuser) > 0" \
304*5696Snw141292 	"	WHEN 1 THEN" \
305*5696Snw141292 	"		raise(ROLLBACK, 'Conflicting w2u namerules')"\
306*5696Snw141292 	"	END; " \
307*5696Snw141292 	"END"
308*5696Snw141292 
309*5696Snw141292 #define	TRIGGER_NAMERULES_UNIQUE_INSERT \
310*5696Snw141292 	"CREATE TRIGGER namerules_unique_insert " \
311*5696Snw141292 	"BEFORE INSERT ON namerules " \
312*5696Snw141292 	"BEGIN " \
313*5696Snw141292 	TRIGGER_NAMERULES_UNIQUE_BODY
314*5696Snw141292 
315*5696Snw141292 #define	TRIGGER_NAMERULES_UNIQUE_UPDATE \
316*5696Snw141292 	"CREATE TRIGGER namerules_unique_update " \
317*5696Snw141292 	"BEFORE INSERT ON namerules " \
318*5696Snw141292 	"BEGIN " \
319*5696Snw141292 	TRIGGER_NAMERULES_UNIQUE_BODY
320*5696Snw141292 
321*5696Snw141292 #define	DB_INSTALL_SQL \
322*5696Snw141292 	TABLE_NAMERULES ";" \
323*5696Snw141292 	INDEX_NAMERULES_W2U ";" \
324*5696Snw141292 	INDEX_NAMERULES_U2W ";" \
325*5696Snw141292 	TRIGGER_NAMERULES_TOLOWER_INSERT ";" \
326*5696Snw141292 	TRIGGER_NAMERULES_TOLOWER_UPDATE ";" \
327*5696Snw141292 	TRIGGER_NAMERULES_UNIQUE_INSERT ";" \
328*5696Snw141292 	TRIGGER_NAMERULES_UNIQUE_UPDATE ";"
329*5696Snw141292 
330*5696Snw141292 #define	DB_VERSION_SQL \
331*5696Snw141292 	"SELECT CASE (SELECT count(*) FROM sqlite_master) WHEN 0 THEN 0 ELSE " \
332*5696Snw141292 	"(CASE (SELECT count(*) FROM sqlite_master WHERE " \
333*5696Snw141292 	"sql = '" TABLE_NAMERULES_v1 "' OR " \
334*5696Snw141292 	"sql = '" INDEX_NAMERULES_W2U_v1 "' OR " \
335*5696Snw141292 	"sql = '" INDEX_NAMERULES_U2W "') " \
336*5696Snw141292 	"WHEN 3 THEN 1 ELSE "\
337*5696Snw141292 	"(CASE (SELECT count(*) FROM sqlite_master WHERE " \
338*5696Snw141292 	"sql = '" TABLE_NAMERULES "' OR " \
339*5696Snw141292 	"sql = '" INDEX_NAMERULES_W2U "' OR " \
340*5696Snw141292 	"sql = '" INDEX_NAMERULES_U2W "' OR " \
341*5696Snw141292 	"sql = '" TRIGGER_NAMERULES_TOLOWER_INSERT "' OR " \
342*5696Snw141292 	"sql = '" TRIGGER_NAMERULES_TOLOWER_UPDATE "' OR " \
343*5696Snw141292 	"sql = \"" TRIGGER_NAMERULES_UNIQUE_INSERT "\" OR " \
344*5696Snw141292 	"sql = \"" TRIGGER_NAMERULES_UNIQUE_UPDATE "\") " \
345*5696Snw141292 	"WHEN 7 THEN 2 ELSE -1 END) END) END AS version;"
346*5696Snw141292 
347*5696Snw141292 /* SQL for upgrading an existing name rules DB.  Includes DB_INSTALL_SQL */
348*5696Snw141292 #define	DB_UPGRADE_FROM_v1_SQL \
349*5696Snw141292 	"CREATE TABLE namerules_new " TABLE_NAMERULES_BODY ";" \
350*5696Snw141292 	"INSERT INTO namerules_new SELECT is_user, is_user, windomain, " \
351*5696Snw141292 	"winname, winname, is_nt4, unixname, w2u_order, u2w_order " \
352*5696Snw141292 	"FROM namerules;" \
353*5696Snw141292 	"DROP TABLE namerules;" \
354*5696Snw141292 	DB_INSTALL_SQL \
355*5696Snw141292 	"INSERT INTO namerules SELECT * FROM namerules_new;" \
356*5696Snw141292 	"DROP TABLE namerules_new;"
357*5696Snw141292 
358*5696Snw141292 #define	DB_VERSION	2
359*5696Snw141292 
360*5696Snw141292 #ifdef __cplusplus
361*5696Snw141292 }
362*5696Snw141292 #endif
363*5696Snw141292 
364*5696Snw141292 
365*5696Snw141292 #endif	/* _SCHEMA_H */
366