Suddenly getting SQL Exceptions when using sql variables in statements - java

I have a SQL query, consisting of different statements (this is a simplified version, which also triggers the error) :
private static String getActiveKeyEventsSql =
"SET #report_model_id = 2; " +
"SELECT MAX(report_ts) AS report_ts " +
"FROM `pulse_data`.`key_event_reports` " +
"WHERE report_model_id = #report_model_id ";
I am trying to call that statement from inside my Java Application:
public static void main(String[] args) throws Exception {
MySQLLayer _db = new MySQLLayer();
Connection _conn = null;
try {
_conn = _db.getConnection();
PreparedStatement getActiveKeyEventsStmt = _conn.prepareStatement(getActiveKeyEventsSql);
ResultSet rs = getActiveKeyEventsStmt.executeQuery();
while (rs.next()) {
LOG.info(rs.getLong("report_ts"));
}
} catch (SQLException e) {
LOG.error("COULD NOT GET MAX REPORT.", e);
} finally {
try {
if (_conn != null && !_conn.isClosed()) {
_conn.close();
}
} catch (SQLException e) {
LOG.info("COULD NOT CLOSE CONNECTION.", e);
}
}
}
But it triggers the following error:
java.sql.SQLException: ResultSet is from UPDATE. No Data.
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1073)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:987)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:982)
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:927)
at com.mysql.jdbc.ResultSetImpl.next(ResultSetImpl.java:6870)
at com.stockpulse.stockstorm.sentiment.JavaTest.main(JavaTest.java:36)
In other places of my application, this schema works just fine. When I copy this statement to the MySQL console, it works just fine.
Here is the String to init the DB:
config.setJdbcUrl(
"jdbc:mysql://" + cred.getHOST() + "/" + cred.getDB()
+ "?allowMultiQueries=true&characterEncoding=utf-8&useUnicode=true&rewriteBatchedStatements=true&relaxAutoCommit=true"
);
Why is JDBC behaving this way out of the sudden?

Try breaking your statement into
a = "SET #report_model_id = 2; ";
b = "SELECT MAX(report_ts) AS report_ts " +
"FROM `pulse_data`.`key_event_reports` " +
"WHERE report_model_id = #report_model_id ";
And do PreparedStatement.addBatch() for each.

Related

Error: Incorrect syntax near (database name)

hi I am getting this error in my Java program. Here is my query. It is working good in SQL server. but getting
Error: Incorrect syntax near 'WebApp'.
private static final String SERVICES =
"SELECT s.Service_ID "
+ ",s.[Location_ID] "
+ ",COALESCE(st.[Service_Type_Name],s.[Service_Name]) AS Service_name "
+ ",st.Service_Type_Name "
+ " FROM [WebApp].[dbo].[Services] s join [WebApp].[dbo].[ServiceTypes] st on s.Service_Type=st.Service_Type_ID "
+ " join WebApp.dbo.Locations l on s.Location_ID=l.Location_ID "
+ " where s.Deleted=0 "
+ " ORDER BY Location_ID ";
and here is my method it is working fine on ms sql server 2008
public List<MAServiceVO> getAddServices() throws CoopCRSAPIException {
ArrayList<MAServiceVO> results = new ArrayList<MAServiceVO>();
MAServiceVO maServiceVO = null;
log.debug("==========IN VendorDAOimpl.java (service)===========");
//int serviceID = 0;
//int prevServiceID = 0;
try {
conn = MSSQLDAOFactory.createConnection();
stmt = conn.prepareStatement(SERVICES);
// stmt.setTimestamp(1, startDate);
// stmt.setTimestamp(2, endDate);
stmt.execute();
rs = stmt.getResultSet();
while (rs.next()) {
// create new service
maServiceVO = new MAServiceVO();
// set service fields
maServiceVO.setServiceID(rs.getInt("Service_ID"));
maServiceVO.setLocationID(rs.getInt("Location_ID"));
maServiceVO.setServiceName(rs.getString("Service_Name"));
maServiceVO.setServiceType(rs.getString("Service_Type_Name"));
log.debug("==========done with VendorDAOimpl.java (service)===========");
}
} catch (SQLException e) {
log.debug(e.getMessage());
throw new CoopCRSAPIException(e.getMessage(), " VendorDAOimpl", "getAddServices", 500);
} finally {
closeConnections("getAddServices");
}
log.debug("&&&&&&&&&&&&&&&&&&&&&");
log.debug("==========finsh===========");
return results;
}
I don't see anything out of whack there. If there a reason you don't have this in a stored procedure instead of pass through sql? I did notice you didn't put square brackets around your final join but that shouldn't make any difference.
Here is your query after stripping off all the extra string parts for java.
SELECT s.Service_ID
, s.[Location_ID]
, COALESCE(st.[Service_Type_Name], s.[Service_Name]) AS Service_name
, st.Service_Type_Name
FROM [WebApp].[dbo].[Services] s
join [WebApp].[dbo].[ServiceTypes] st on s.Service_Type = st.Service_Type_ID
join [WebApp].[dbo].[Locations] l on s.Location_ID = l.Location_ID
where s.Deleted = 0
ORDER BY Location_ID;

MySQLSyntaxErrorException while trying to update database

I'm doing an app for school project and I came across this error I've tried to figure it out but I can't seem to fix it.
Let me explain the problem first, basically I'm trying to update previously created user. Initially the profile has only username and a password. I want the user to be able to add whatever details he wishes to later on once he has created his own profile.
I have one class which has the database connectivity and update Profile method. The other class is a jFrame where user can input some data into textfields and the intention is that it will be inserted into fields for existing profile within the database (Initially those fields are declared as null).
Below you can see my DBConnect class which contain the Login method and UpdateProfile method. In the login method I'm creating a profile object which holds all the variables and methods such as getUsername, getPassword etc.
public class DBConnect {
private Connection dbConnection;
public Profile profile;
public DBConnect() {
try {
dbConnection = DriverManager.getConnection("jdbc:mysql://localhost:3306/prototype?user=root");
} catch (Exception ex) {
System.out.println("Connection failed :" + ex);
}
}
public void Login() {
profile = new Profile(LoginWindow.usernameField.getText(), LoginWindow.passwordField.getText());
Statement userQuery = null;
try {
//Look for the user with valid username and password
userQuery = dbConnection.createStatement();
ResultSet rs = userQuery.executeQuery("Select * FROM Profile WHERE pName = \"" + profile.getUsername() + "\" and password = \"" + profile.getPassword() + "\"");
if (rs.next()) {
profile.isLoggedin(true);
} else {
profile.isLoggedin(false);
}
} catch (SQLException ex) {
profile.isLoggedin(false);
System.out.println(ex);
} finally {
try {
if (userQuery != null) {
userQuery.close();
}
} catch (SQLException ex) {
System.out.println("Failed to close login query");
}
}
}
public void updateProfile(String _height, String _weight, String _goalWeight, String _age) {
Statement updateQuery = null;
try {
updateQuery = dbConnection.createStatement();
updateQuery.executeUpdate("UPDATE Profile SET height='" + _height + "',weight='" + _weight + "',goalWeight='" + _goalWeight + "',age='" + _age + "' WHERE pName =" + profile.getUsername());
} catch (SQLException ex) {
System.out.println(ex);
} finally {
try {
if (updateQuery != null) {
updateQuery.close();
}
} catch (SQLException ex) {
System.out.println("Failed to close updateCustomer query");
}
}
}
}
I'm trying to update some of the fields that were empty with the Update Profile method and to get the profile that I want to update I wrote "WHERE pName =" + profile.getUsername());" in order to retrieve the record of the user.
Finally in the EditProfile jFrame I wrote this method to pass on the parameters for the updateProfile methods.
private void saveButtonActionPerformed(java.awt.event.ActionEvent evt) {
LoginWindow.dbc.updateProfile(heightTextField.getText(), weightTextField.getText(), goalWeightTextField.getText(), ageTextField.getText());
}
Everything compiles but I'm having mySQLSyntaxError which is:
com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'Admin' in 'where clause'
The database is not updated and I don't know how to fix it.
My assumptions is that there is a problem with "WHERE pName =" + profile.getUsername());" in updateProfile declaration. The "Admin" is the result of profile.getUsername(); and its the actual username of currently logged in user.
Please help.
You have a little syntax error: Your line
updateQuery.executeUpdate("UPDATE Profile SET height='" + _height + "',weight='" + _weight + "',goalWeight='" + _goalWeight + "',age='" + _age + "' WHERE pName =" + profile.getUsername());
should read
updateQuery.executeUpdate("UPDATE Profile SET height='" + _height + "',weight='" + _weight + "',goalWeight='" + _goalWeight + "',age='" + _age + "' WHERE pName ='" + profile.getUsername()) + "'";
(You need to enclose the pName parameter with single quotes.)
...and you really need to start using PreparedStatement as others also suggested.
that exactly the problem. try that:
ResultSet rs = userQuery.executeQuery("Select * FROM Profile WHERE pName = '" + profile.getUsername() + "' and password = '" + profile.getPassword() + "' ");

Java connection to database

I have exhausted all avenues to sort out this problem, but to no avail. I have installed "SQL Management Studio 2012" and created a dummy database and methods, but I'm still getting a "null point exception pointer". Java and JDBC is set under user variables.
Here are the screen shots and code.
Static {
// standard code to open a connection and statement to SQL Server database
try {
// Create a variable for the connection string.
String connectionUrl = "jdbc:sqlserver://SQL-SERVER;"
+ "databaseName=ItunesDB;integratedSecurity=true;";
// Establish the connection.
Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
con = DriverManager.getConnection(connectionUrl);
} // Handle any errors that may have occurred.
catch (SQLException sqle) {
System.out.println("Sql Exception :" + sqle.getMessage());
} catch (ClassNotFoundException e) {
System.out.println("Class Not Found Exception :" + e.getMessage());
}
}
public static String listAll() {
String output = "";
try {
stmt = con.createStatement();
ResultSet res = stmt.executeQuery("SELECT * FROM LibraryTable");
while (res.next()) { // there is a result
// the name field is the thrid one in the ResultSet
// Note that with ResultSet we count the fields starting from 1
output += res.getString(1) + " " + res.getString(2) + " - "
+ res.getString(3) + " " + res.getString(4) + " "
+ res.getString(5) + "\n";
}
} catch (Exception e) {
System.out.println(e);
return null;
}
return output;
}
public static String getName(String key) {
try {
SELECT * FROM LibraryTable WHERE key = '04'
stmt = con.createStatement();
ResultSet res = stmt.executeQuery("SELECT * FROM LibraryTable WHERE ID = '" + key + "'");
if (res.next()) { // there is a result
// the name field is the second one in the ResultSet
// Note that with ResultSet we count the fields starting from 1
return res.getString(2);
} else {
return null;
}
} catch (Exception e) {
System.out.println(e);
return null;
}`enter code here`
The database information:
Dummy Database
ID Name Artist Quantity Price Rating Playcount
What do I need to do to fix this?
Re install sql server in mixed mode . Then go to SQL Server configuration manager and checks is the TCP/Ip is enable . IF not enable it and restart the service. Then add sqljdbc jar in your project . Then try this code
Connection con = null;
try {
Class.forName(
"com.microsoft.sqlserver.jdbc.SQLServerDriver");
con = DriverManager.getConnection(
"jdbc:sqlserver://localhost:1433;"
+ "user=sa;password=HerongYang;"
+ "database=AdventureWorksLT");
}
user is always sa because it is the system administrator

Database - [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified

I'm getting the following errors messages when I'm trying to run my database program. This is one of the files I'm getting issues from what I'm understanding.
Thanks in advance for your help!
java.sql.SQLException: [Microsoft][ODBC Driver Manager] Data source name not found and no default driver specified
at sun.jdbc.odbc.JdbcOdbc.createSQLException(JdbcOdbc.java:6964)
at sun.jdbc.odbc.JdbcOdbc.standardError(JdbcOdbc.java:7121)
at sun.jdbc.odbc.JdbcOdbc.SQLDriverConnect(JdbcOdbc.java:3080)
at sun.jdbc.odbc.JdbcOdbcConnection.initialize(JdbcOdbcConnection.java:323)
at sun.jdbc.odbc.JdbcOdbcDriver.connect(JdbcOdbcDriver.java:174)
at java.sql.DriverManager.getConnection(DriverManager.java:571)
at java.sql.DriverManager.getConnection(DriverManager.java:233)
at data.DbManager.getAccessDbConnection(DbManager.java:201)
at data.DbManager.<init>(DbManager.java:26)
at user.Frame.<init>(Frame.java:10)
at user.MainP8.main(MainP8.java:16)
DbManager.java
package data;
import java.sql.*;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
public class DbManager {
//Add to beginning of MS Access DB URL
private String ACCESS_DB_URL_PREFIX =
"jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=";
//Add to end of MS Access DB URL
private final String ACCESS_DB_URL_SUFFIX = ";DriverID=22;READONLY=false;}";
//File name of database
private final String MY_DB_NAME = "WebsiteDatabase.mdb";
private String fileName;
private Connection myConnection;
//constructor
public DbManager() {
try {
myConnection = getAccessDbConnection(MY_DB_NAME);
myConnection.setAutoCommit(true);
DatabaseMetaData md = myConnection.getMetaData();
} catch (SQLException ex) {
Logger.getLogger
(DbManager.class.getName()).log(Level.SEVERE, null, ex);
JOptionPane.showMessageDialog(null,
"The database could not be located. Please select the database"
+ " file you wish to connect to.",
"Database Error", JOptionPane.ERROR_MESSAGE);
JFileChooser chooser = new JFileChooser();
chooser.showOpenDialog(chooser);
fileName = chooser.getSelectedFile().toString();
try {
myConnection = getAccessDbConnection(fileName);
myConnection.setAutoCommit(true);
DatabaseMetaData md = myConnection.getMetaData();
} catch (SQLException ex1) {
Logger.getLogger
(DbManager.class.getName()).log(Level.SEVERE, null, ex1);
JOptionPane.showMessageDialog(null,
"The database could not be opened", "Fatal Error",
JOptionPane.ERROR_MESSAGE);
}
}
}
//"destructor" method to release the database connection
public void close() {
try {
myConnection.close();
} catch (SQLException ex) {
Logger.getLogger
(DbManager.class.getName()).log(Level.SEVERE, null, ex);
}
}
//public methods to access the database
public void insert(Website w) throws SQLException {
String sql;
//build SQL statement
sql = "INSERT INTO Websites";
sql += " (COMPANY_NAME, COMP_ASSETS, YR_FOUNDED, URL_ADD, ALEXA_RANK)";
sql += " VALUES (";
sql += "'" + w.getCompName() + "',";
sql += w.getAssets() + ",";
sql += " #" +w.getFounded() + "#,";
sql += " '" + w.getUrl() + "',";
sql += w.getAlexaRank() + ");";
insertRecord(sql);
}
public void update(Website w) throws SQLException {
String sql;
//SimpleDateFormat date = new SimpleDateFormat("yyyy-MM-dd");
//date.parse(w.getFounded());
// "#"
//build SQL statement
sql = "UPDATE WebsiteS SET";
sql += " COMPANY_NAME = '" + w.getCompName() + "',";
sql += " COMP_ASSETS = " + w.getAssets() + ",";
sql += " YR_FOUNDED = #" + w.getFounded() + "#,";
sql += " URL_ADD = '" + w.getUrl() + "',";
sql += " ALEXA_RANK = " + w.getAlexaRank() ;
sql += " WHERE ID = " + w.getId() + ";";
updateRecord(sql);
}
public void delete(Website w) throws SQLException {
String sql;
sql = "DELETE * FROM Websites WHERE ID = " + w.getId() + ";";
deleteRecord(sql);
}
public String[] getWebsiteList() throws SQLException {
String strSql = "SELECT COMPANY_NAME FROM Websites;";
PreparedStatement ps = myConnection.prepareStatement(strSql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery();
rs.last();
int rowCount = rs.getRow();
String[] items = new String[rowCount];
try {
rs.beforeFirst();
int i = 0;
while(rs.next()) {
items[i] = rs.getString("COMPANY_NAME");
i++;
}
} catch (Exception ex){
JOptionPane.showMessageDialog(null,
"getWebsiteList: Unable to read website names: " + ex.getMessage());
System.out.println(ex.getStackTrace());
System.out.println(ex.getLocalizedMessage());
}
return items;
}
public int[] getWebsiteIds() throws SQLException {
int[] id;
String strSql = "SELECT ID FROM Websites;";
PreparedStatement ps = myConnection.prepareStatement(strSql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery();
rs.last();
int rowCount = rs.getRow();
id = new int[rowCount];
try {
rs.beforeFirst();
int i = 0;
while(rs.next()) {
id[i] = rs.getInt("ID");
i++;
}
} catch (Exception ex) {
JOptionPane.showMessageDialog(null,
"getWebsiteIDs: Unable to read Website IDs: " + ex.getMessage());
System.out.println(ex.getStackTrace());
System.out.println(ex.getLocalizedMessage());
}
return id;
}
public Website getWebsite(int wId) throws SQLException {
String[] rec;
String strSql = "SELECT * FROM Websites WHERE ID = " + wId + ";";
Website website = null;
PreparedStatement ps = myConnection.prepareStatement(strSql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
ResultSet rs = ps.executeQuery();
ResultSetMetaData rsMeta = rs.getMetaData();
int columns = rsMeta.getColumnCount();
rec = new String[columns];
try {
rs.beforeFirst();
while(rs.next()) {
for (int i = 0; i < columns; i++) {
rec[i] = rs.getString(i + 1);
}
}
//use the data to build the Website object
website = new Website(
//Integer.parseInt(rec[0]),
rec[0],
rec[1],
rec[2],
rec[3],
rec[4],
rec[5]
);
} catch (SQLException ex) {
System.out.println(ex.getStackTrace());
System.out.println(ex.getLocalizedMessage());
}
return website;
}
//private method to establish database connection
private Connection getAccessDbConnection(String fileName)
throws SQLException {
try {
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
} catch (ClassNotFoundException ex) {
System.err.println("JdbcOdbc Bridge Driver not Found");
JOptionPane.showMessageDialog(null, ex.getMessage(), "Driver Error",
JOptionPane.ERROR_MESSAGE);
System.exit(0);
}
String databaseURL = ACCESS_DB_URL_PREFIX + fileName
+ ACCESS_DB_URL_SUFFIX;
return DriverManager.getConnection(databaseURL);
}
//private methods to access the database
private void insertRecord(String strSql) throws SQLException {
Statement st = myConnection.createStatement();
try {
st.execute(strSql);
} catch (SQLException ex) {
System.err.println(ex.getStackTrace());
System.err.println(ex.getMessage());
System.err.println(ex.getLocalizedMessage());
}
st.close();
}
private void updateRecord(String strSql) throws SQLException {
//use prepared statement to ensure that the result set is editable
PreparedStatement ps = myConnection.prepareStatement(strSql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
try {
ps.execute();
} catch (SQLException ex) {
System.err.println(ex.getStackTrace());
System.err.println(ex.getMessage());
System.err.println(ex.getLocalizedMessage());
}
}
private void deleteRecord(String strSql) throws SQLException {
PreparedStatement ps = myConnection.prepareStatement(strSql,
ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_UPDATABLE);
try {
ps.execute();
} catch (SQLException ex) {
System.err.println(ex.getStackTrace());
System.err.println(ex.getMessage());
System.err.println(ex.getLocalizedMessage());
}
}
}
Check
You have the MS Access driver installed
The descriptive string you use is correct, "Microsoft Access Driver (.mdb)" It has to be exact, check in the Drivers tab in the ODBC control panel app, mine for example is (.mdb, *.accdb)
Check you are not mixing a 64 bit JVM with a 32 bit driver or vice versa.
If you are using a 32-bit operating system then I think there would be no such issue, but if you are using a 64-bit OS, then follow these steps:
Download 64-bit access driver from here.
Run setup, then restart your computer.
Go to Start -> Control Panel -> Administrative Tools -> (Data Sources) ODBC -> System DSN.
Click the "add" button.
Choose "Microsoft Access Driver (*.mdb)"
Provide any data source name, then click "create".
Choose the directory where you want your database (note: the directory should be same as directory of source directory for your Java programs)
Start command prompt for execution of 64bit database connectivity.
Copy C:\WINDOWS\SYSWOW64.exe in run dialog box of your computer, then their start your compilation and execution of your database program.
I had this problem on one of my sites when I upgraded my laptop from 32-bit Windows XP to 64-bit Windows 7. I overcame this problem by creating a 32-bit application pool (Application Pools > Advanced Settings > Enable 32-bit Applications = True) and running my site that way. Even with Microsoft Office installed, the drivers are not installed for 64-bit site access. Hope this helps someone
If you are using using a 64-bit OS, then follow these steps:
Download 64-bit access driver from http://www.microsoft.com/en-in/download/details.aspx?id=13255.
Run setup, then restart your computer.
If you are an application developer using ODBC to connect to Microsoft Office Access data, set the Connection String to “Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=path to mdb/accdb file”
If you are an application developer using ODBC to connect to Microsoft Office Excel data, set the Connection String to “Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=path to xls/xlsx/xlsm/xlsb file”

prepared SQL statements in java

I'm trying to connect to a database and update a table in it using prepared statements in a java program -- the database is called "database" and in that there is another folder called Views in which the table ("TABLE") that I'm trying to update is. Here is my code:
public void updateTable(Map<String, String> mp) throws SQLException {
String URL = "jdbc:oracle:thin:#localhost:1500:orcl";
String USER = "user";
String PASS = "password";
Connection con = DriverManager.getConnection(URL, USER, PASS);
PreparedStatement updateTableName = null;
String updateString =
"update database.Views.TABLE " +
"set TABLENAME = ? " +
"where TABLENAME = ?";
try {
con.setAutoCommit(false);
updateTableName = con.prepareStatement(updateString);
for (Map.Entry<String, String> e : mp.entrySet())
{
updateTableName.setString(1, e.getValue());
updateTableName.setString(2, e.getKey());
updateTableName.executeUpdate();
con.commit();
}
} catch (SQLException e) {
if (con != null)
{
try {
System.err.print("Transaction is being rolled back");
con.rollback();
} catch (SQLException excep) {
}
}
} finally {
if (updateTableName != null)
{
updateTableName.close();
}
con.setAutoCommit(true);
}
con.close();
}
Whenever I run the code it displays "transaction is being rolled back." Any idea what errors I have in the try statement? Thanks in advance!
EDIT: when I change it to print the exception, it reads ORA-00971: missing SET keyword.
"update database.Views.TABLE" +
"set TABLENAME = ?" +
"where TABLENAME = ?";
The value of this string is
update database.Views.TABLEset TABLENAME = ?where TABLENAME = ?
That is not valid SQL.
You should try logging the SQLException you catch in the 1st catch block, that would give you a clear indication of what the problem is.
In any case, TABLE is a SQL-reserved keyword and you should not be allowed to name a table like that - at least try renaming it to TABLE1 for lack of a better name.
Ok I figured it out, #Spiff I did change it to the simplest query with just update TABLE1, but I also took out the :
String updateString =
"update database.Views.TABLE " +
"set TABLENAME = ? " +
"where TABLENAME = ?";
and combined it into one line with the
updateTableName = con.prepareStatement(updateString)
to make :
updateTableName = con.prepareStatement(update TABLE1 set TABLENAME = ? where TABLENAME = ?);

Categories