Oracle keeps giving me an invalid identifier error when I clearly have identified the variable.
//get parameters from the request
String custID=request.getParameter("cust_ID");
String saleID=request.getParameter("sale_ID");
String firstName=request.getParameter("first_Name");
String mInitial=request.getParameter("mI");
String lastName=request.getParameter("last_Name");
String streetName=request.getParameter("street");
String city=request.getParameter("city");
String state=request.getParameter("state");
String zipCode=request.getParameter("zip_Code");
String DOB2=request.getParameter("DOB");
String agentID=request.getParameter("agent_ID");
String homePhone=request.getParameter("home_Phone");
String cellPhone=request.getParameter("cell_Phone");
String profession=request.getParameter("profession");
String employer=request.getParameter("employer");
String referrer=request.getParameter("referrer");
query =
"UPDATE customer"
+ " SET customer.cust_ID=custID, customer.sale_ID=saleID, customer.first_Name=firstName, customer.mI=mInitial, customer.last_Name=lastName, customer.street_Name=streetName, customer.city=city, customer.state=state, customer.zip_Code=zipCode,customer. DOB=DOB2, customer.agent_ID=agentID, customer.home_Phone=homePhone, customer.cell_Phone=cellPhone, customer.profession=profession, customer.employer=employer, customer.referrer=referrer"
+ " WHERE customer.cust_ID=custID " ;
preparedStatement = conn.prepareStatement(query);
preparedStatement.executeUpdate();
SQL TABLE
CREATE TABLE customer
(cust_ID NUMBER NOT NULL,
sale_ID NUMBER NOT NULL,
first_NameVARCHAR2(30) NOT NULL,
mI VARCHAR2(2) ,
last_Name VARCHAR2(50) NOT NULL,
street_Name VARCHAR2(50) ,
city VARCHAR2(30) NOT NULL,
state VARCHAR2(50) NOT NULL,
zip_Code VARCHAR2(5) NOT NULL,
DOB DATE ,
agent_ID NUMBER ,
home_Phone VARCHAR2(12) UNIQUE,
cell_Phone VARCHAR2(12) UNIQUE,
profession VARCHAR2(30) ,
employer VARCHAR2(30) ,
referrer VARCHAR2(30)
);
Your code is not doing what you think it is. Look at this:
query =
"UPDATE customer"
+ " SET customer.cust_ID=custID, customer.sale_ID=saleID, customer.first_Name=firstName, customer.mI=mInitial, customer.last_Name=lastName, customer.street_Name=streetName, customer.city=city, customer.state=state, customer.zip_Code=zipCode,customer. DOB=DOB2, customer.agent_ID=agentID, customer.home_Phone=homePhone, customer.cell_Phone=cellPhone, customer.profession=profession, customer.employer=employer, customer.referrer=referrer"
+ " WHERE customer.cust_ID=custID "
The content of query at this point is exactly what will be sent to the database. JSP will not magically fill in custID, saleID (etc...) for you before sending the query to the database. Because of this, Oracle has no sweet clue what custID is (it certainly isn't the name of some other column in the customer table). Hence, you receive the invalid identifier error.
I think you were trying to do this:
query =
"UPDATE customer"
+ " SET customer.cust_ID=" + custID + ", customer.sale_ID=" + saleID + ...
Like duffymo mentioned, this is asking for serious SQL-injection trouble (just think of the values that the client could submit in order to hijack your SQL via the custID field). The better way is to use parameters on a PreparedStatement:
query =
"UPDATE customer"
+ " SET customer.cust_ID=?, customer.sale_ID=? ...";
PreparedStatement statement = conn.prepareStatement(query);
statement.setString(1, custID);
statement.setString(2, saleID);
statement.executeUpdate();
I'd recommend not using scriplets in your JSPs. Learn JSTL as quickly as you can.
The answer seems pretty obvious: your parameters are all Strings, but the Oracle schema has some Data and Number types. You've got to convert to the correct type when you INSERT.
This code is begging for a SQL injection attack. You don't do any binding or validation before you INSERT. You couldn't possibly be less secure than this. I hope you don't intend to use this site for anything on the web.
A better approach would take the scriptlet code out of the JSP, use only JSTL to write it, and introduce a servlet and some other layers to help with binding, validation, security, etc.
I think in the sql query you have entered space in between customer,DOB.
customer. DOB=DOB2
Related
I am having code something like this.
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
Calculation of fullTableName is something like:
public String getFullTableName(final String table) {
if (this.schemaDB != null) {
return this.schemaDB + "." + table;
}
return table;
}
Here schemaDB is the name of the environment(which can be changed over time) and table is the table name(which will be fixed).
Value for schemaDB is coming from an XML file which makes the query vulnerable to SQL injection.
Query: I am not sure how the table name can be used as a prepared statement(like the name used in this example), which is the 100% security measure against SQL injection.
Could anyone please suggest me, what could be the possible approach to deal with this?
Note: We can be migrated to DB2 in future so the solution should compatible with both Oracle and DB2(and if possible database independent).
JDBC, sort of unfortunately, does not allow you to make the table name a bound variable inside statements. (It has its reasons for this).
So you can not write, or achieve this kind of functionnality :
connection.prepareStatement("SELECT * FROM ? where id=?", "TUSERS", 123);
And have TUSER be bound to the table name of the statement.
Therefore, your only safe way forward is to validate the user input. The safest way, though, is not to validate it and allow user-input go through the DB, because from a security point of view, you can always count on a user being smarter than your validation.
Never trust a dynamic, user generated String, concatenated inside your statement.
So what is a safe validation pattern ?
Pattern 1 : prebuild safe queries
1) Create all your valid statements once and for all, in code.
Map<String, String> statementByTableName = new HashMap<>();
statementByTableName.put("table_1", "DELETE FROM table_1 where name= ?");
statementByTableName.put("table_2", "DELETE FROM table_2 where name= ?");
If need be, this creation itself can be made dynamic, with a select * from ALL_TABLES; statement. ALL_TABLES will return all the tables your SQL user has access to, and you can also get the table name, and schema name from this.
2) Select the statement inside the map
String unsafeUserContent = ...
String safeStatement = statementByTableName.get(usafeUserContent);
conn.prepareStatement(safeStatement, name);
See how the unsafeUserContent variable never reaches the DB.
3) Make some kind of policy, or unit test, that checks that all you statementByTableName are valid against your schemas for future evolutions of it, and that no table is missing.
Pattern 2 : double check
You can 1) validate that the user input is indeed a table name, using an injection free query (I'm typing pseudo sql code here, you'd have to adapt it to make it work cause I have no Oracle instance to actually check it works) :
select * FROM
(select schema_name || '.' || table_name as fullName FROM all_tables)
WHERE fullName = ?
And bind your fullName as a prepared statement variable here. If you have a result, then it is a valid table name. Then you can use this result to build a safe query.
Pattern 3
It's sort of a mix between 1 and 2.
You create a table that is named, e.g., "TABLES_ALLOWED_FOR_DELETION", and you statically populate it with all tables that are fit for deletion.
Then you make your validation step be
conn.prepareStatement(SELECT safe_table_name FROM TABLES_ALLOWED_FOR_DELETION WHERE table_name = ?", unsafeDynamicString);
If this has a result, then you execute the safe_table_name. For extra safety, this table should not be writable by the standard application user.
I somehow feel the first pattern is better.
You can avoid attack by checking your table name using regular expression:
if (fullTableName.matches("[_a-zA-Z0-9\\.]+")) {
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
}
It's impossible to inject SQL using such a restricted set of characters.
Also, we can escape any quotes from table name, and safely add it to our query:
fullTableName = StringEscapeUtils.escapeSql(fullTableName);
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
stmt.setString(1, addressName);
StringEscapeUtils comes with Apache's commons-lang library.
I think that the best approach is to create a set of possible table names and check for existance in this set before creating query.
Set<String> validTables=.... // prepare this set yourself
if(validTables.contains(fullTableName))
{
final PreparedStatement stmt = connection
.prepareStatement("delete from " + fullTableName
+ " where name= ?");
//and so on
}else{
// ooooh you nasty haker!
}
create table MYTAB(n number);
insert into MYTAB values(10);
commit;
select * from mytab;
N
10
create table TABS2DEL(tname varchar2(32));
insert into TABS2DEL values('MYTAB');
commit;
select * from TABS2DEL;
TNAME
MYTAB
create or replace procedure deltab(v in varchar2)
is
LvSQL varchar2(32767);
LvChk number;
begin
LvChk := 0;
begin
select count(1)
into LvChk
from TABS2DEL
where tname = v;
if LvChk = 0 then
raise_application_error(-20001, 'Input table name '||v||' is not a valid table name');
end if;
exception when others
then raise;
end;
LvSQL := 'delete from '||v||' where n = 10';
execute immediate LvSQL;
commit;
end deltab;
begin
deltab('MYTAB');
end;
select * from mytab;
no rows found
begin
deltab('InvalidTableName');
end;
ORA-20001: Input table name InvalidTableName is not a valid table name ORA-06512: at "SQL_PHOYNSAMOMWLFRCCFWUMTBQWC.DELTAB", line 21
ORA-06512: at "SQL_PHOYNSAMOMWLFRCCFWUMTBQWC.DELTAB", line 16
ORA-06512: at line 2
ORA-06512: at "SYS.DBMS_SQL", line 1721
I am trying to add a new record to a table from Derby database. I need to use the record number in one of its fields. E.g. I need to save a path to the image in photo field. And the name of the image must corresponds its id. For example 1.jpg. I was trying this statement (file extention is not used in this example):
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO Users (name, lastname, email, address, password, photo, lastvisit, status) VALUES ('" + name + "','" + lastname + "','" + email + "','" + address + "','" + DigestUtils.toMd5(password) + "', id, '" + now + "','user')");
But I get an error:java.sql.SQLSyntaxErrorException: Column 'ID' is either not in any table in the FROM list...
But this column definitely exists. What is the reason of the error?
Well the short answer imho is that you cannot do that in SQL.
In your table Users, I guess that your id column is an auto incremented primary key. What you can do is insert your record and then get the last id generated for this insert statement. Then you have to perform an update query to set the value of your photo column.
By the way, definitely learn to use placeholders in prepared statements
I'm not a specialist of Derby but browsing the doc I found how you can get the generated columns.
pstmt.execute(sql, Statement.RETURN_GENERATED_KEYS);
ResultSet keys = pstmt.getGeneratedKeys();
keys.next();
int id = keys.getInt();
I am developing a java web service that is deployed in wildly. It is connected to a postgresql database.
In this database, I have a table called xx_activity. In it there is a column called "id", which is also the primary key.
Here is the query used to create the table:
CREATE TABLE xx_activity
(
id serial NOT NULL,
baseitemid integer
);
to connect to this table, I use the following java code:
conn = postgresVoyateDBConnection();
query = conn.prepareStatement("select id, baseitemid" +
"from xx_activity " +
"where \"id\" = ? ");
query.setInt(1, id);
ResultSet rs = query.executeQuery();
However, when I call the method that includes this code, I get an error:
org.postgresql.util.PSQLException: ERROR: column "id" does not exist
Position: 8
This is confusing because I certainly have this column. i added escape characters as per this answer, but it did not solve the issue.
Also note that queries without the where clause, like:
conn = postgresVoyateDBConnection();
query = conn.prepareStatement("select id, baseitemid " +
"from xx_activity");
ResultSet rs = query.executeQuery();
work perfectly.
I have also tried without using escape characters but it gives the same error. I also checked in pgadmin and there is no trailing space in the column name, neither are there any upper case letters involved (in which case, the other select query shouldn't have worked?).
How can this be fixed?
Fixed this, the issue was a missing space. After the first line of the query, there needs to be a space as belows:
query = conn.prepareStatement("select id, baseitemid " +
"from xx_activity " +
"where \"id\" = ? ");
EDIT: escape charactors not needed for id; so final answer should be:
query = conn.prepareStatement("select id, baseitemid " +
"from xx_activity " +
"where id = ? ");
Okay, so I just started JDBC with derby client and I'm kind of new with it.
I set column ID as primary key with int as it's data type. However, I'm not sure if I should include myStatement.setString(1, ?); because I thought it should Auto Increment but it looks like it's not doing it.
Here's my Grab file details:
create table "ADMIN1".STUDENTPERSONALDETAILS
(
ID INTEGER not null primary key,
STUDENTID VARCHAR(10) not null,
LASTNAME VARCHAR(50) not null,
FIRSTNAME VARCHAR(50) not null,
MIDDLENAME VARCHAR(50) not null,
PLACEOFBIRTH VARCHAR(200) not null,
DOB VARCHAR(50) not null,
GENDER VARCHAR(4) not null,
CIVILSTATUS VARCHAR(7) not null,
RELIGION VARCHAR(15) not null,
NATIONALITY VARCHAR(20) not null
)
How can I correct my PreparedStatement or My Table in such a way that adding of value for column ID will be automatic so that I can start setString(2, studentID) and avoid getting error about the number of columns not matching with what was supplied?
Here's my code:
addButton.addActionListener(new ActionListener () {
#Override
public void actionPerformed(ActionEvent e) {
try {
String myDbUrl = "jdbc:derby://localhost:1527/Enrollment"; //stores url to string
String userName = "admin1";
String Password = "admin1";
Connection myDBConnection = DriverManager.getConnection(myDbUrl, userName, Password);
String myQuery = "INSERT INTO STUDENTPERSONALDETAILS"
+ "(STUDENTID,LASTNAME,FIRSTNAME,MIDDLENAME,PLACEOFBIRTH,DOB,GENDER,CIVILSTATUS,RELIGION,NATIONALITY) "
+ "VALUES(?,?,?,?,?,?,?,?,?,?) ";
String adminissionNo ;
String studentID = tfStudentId.getText().toString();
String lastName = tfLastName.getText().toString();
String firstName = tfFirstName.getText().toString();
String middleName = tfMiddleName.getText().toString();
String placeOfBirth = tfPob.getText().toString();
String dateOfBirth = listDOB.getSelectedItem().toString();
String gender = listGender.getSelectedItem().toString();
String civilStatus = listCivilStatus.getSelectedItem().toString();
String religion = listReligion.getSelectedItem().toString();
String nationality = listNationality.getSelectedItem().toString();
PreparedStatement myStatement = myDBConnection.prepareStatement(myQuery);
myStatement.setString(2, lastName);
myStatement.setString(3, firstName);
myStatement.setString(4, middleName);
myStatement.setString(5, placeOfBirth);
myStatement.setString(6, dateOfBirth);
myStatement.setString(7, gender);
myStatement.setString(8, civilStatus);
myStatement.setString(9, religion);
myStatement.setString(10, nationality);
boolean insertResult = myStatement.execute();
if(insertResult == true)
JOptionPane.showMessageDialog(null, "Successfully Added Information");
else
JOptionPane.showMessageDialog(null, "Encountered an error while inserting data");
}
catch(SQLException ex) {
JOptionPane.showMessageDialog(null, ex.toString());
}
}
});
Is it necessary to include myStatement.setString(1, integervaluehere) for Primary Keys? Isn't it supposed to autoincrement?
I'd appreciate any explanation because I just started learning the basics of PreparedStatements recently.
I tried counting the columns and tried 10 and 11 lines of myStatement.setString(), but still can't get it to insert data because of mismatch.
Thanks in advance.
You need to mention 'auto increment' explicitly.
Or you can write your own java code to track the Id for each table and whenever you ask the method to give the ID it will return lastID + 1.
But, I think now you can go with auto_increment option.
If you want it to autoincrement you need to say so in the column definition, and you haven't.
I don't know what 'default 1' in your title is supposed to mean, as you haven't mentioned it in your question, but you can't have a default value and autoincrement. It doesn't make sense.
I don't know what 'store seed 1' means either, in your edit.
When you have a column with a default value you want to rely on, or autoincrement, you don't mention it at all in the INSERT statement, so there is no positional argument to set.
First, set the primary identifier column to autoincrement. Since your query already excludes the primary key, you then only have to change the PreparedStatement indexes to match the number of parameters in your query starting from one.
Since you have 10 columns in addition to the primary ID column, your PreparedStatement might look something like the following:
PreparedStatement myStatement = myDBConnection.prepareStatement(myQuery);
myStatement.setString(1, studentId);
myStatement.setString(2, lastName);
myStatement.setString(3, firstName);
myStatement.setString(4, middleName);
myStatement.setString(5, placeOfBirth);
myStatement.setString(6, dateOfBirth);
myStatement.setString(7, gender);
myStatement.setString(8, civilStatus);
myStatement.setString(9, religion);
myStatement.setString(10, nationality);
Note that you do not need to have the instruction, myStatement.setInt(1, primaryId);, once you have changed the primary key in your table to auto-increment. However, if you elect to keep the primary key as non-autoincrementing, then you must explicitly specify the primary key value and provide a parameter in your query to insert that data.
If you're using MySQL Workbench, which if you're not, I highly recommend because it just works. You have to choose Auto-Increment as a characteristic of that column. If you want your column to auto increment, when creating columns in your database, check the option Auto-Increment, sometimes written as AI.
Hi I'm doing a query in java, i have java and posgres connected with the driver 9.3-1102-jdbc41
This is my query: query = "SELECT * FROM" +"\"users\" "+ " where user="+"'"+name+"'"+"and pass =" +"'"+pass+"'";
when I run it, this error appears:
Relation "users name" doesn't exist
Here and in others sites a possible solution is checking the quotes or the capital letters.
But I´m sure about the capital letters and this is what I tried:
query = "SELECT * FROM" +"\"users\" "+ " where user="+"'"+name+"'"+"and pass =" +"'"+pass+"'";
query = "SELECT * FROM users where user="+"'"+name+"'"+"and pass =" +"'"+pass+"'";
query = "SELECT * FROM" +"\"sysmar.users\" "+ " where user="+"'"+name+"'"+"and pass =" +"'"+pass+"'";
Error relation users does not exist
"SELECT * FROM users where user="+name+"and pass =" +pass;
syntax error near to pass
Thanks in advance for your answers and time
try:
"SELECT * FROM users where \"user\" ='"+name+"'and pass ='" +pass+"'";
But it's harmful for sql injection. See PreparedStatements.
For PostgreSQL you shouldn't need to put quotes around the table name unless it's a reserved keyword. Users isn't a keyword, but user just so happens to be one of them.
Your query is hard enough to read with the extra concatenation operations and spacing issues. Perhaps there is a syntax error and you just need to clean it up:
q = "SELECT * FROM users WHERE \"user\" = '" + name + "' AND pass = '" + pass + "'";
You want the final evaluated string to look like (for example):
SELECT * FROM users WHERE "user" = 'cory' AND pass = '12345';
But as others have mentioned, you should also switch to using prepared statements. This code is probably vulnerable to SQL injection attacks.
You really shouldn't concatenate variables with SQL queries, you are becoming vulnerable to SQL injection then. You better be using Prepared Statements which will allow you to write queries in more readable and secure fashion.
Connection conn = DriverManager.getConnection(...);
String queryString = "SELECT * FROM users WHERE user = ? AND pass = ?";
PreparedStatement query = conn.prepareStatement(queryString);
query.setString(1, name);
query.setString(2, password);
ResultSet result = query.executeQuery();