What's wrong this T-SQL query :
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim SQLData As New System.Data.SqlClient.SqlConnection("Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True")
Dim cmdSelect As New System.Data.SqlClient.SqlCommand("SELECT COUNT(*) FROM Table1 WHERE Name ='" + TextBox1.Text + "'", SQLData)
SQLData.Open()
If cmdSelect.ExecuteScalar > 0 Then
Label1.Text = "You have already voted this service"
Return
End If
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con.Open()
cmd.Connection = con
cmd.CommandText = "INSERT INTO Tabel1 (Name) VALUES('" & Trim(Label1.Text) & "')"
cmd.ExecuteNonQuery()
Label1.Text = "Thank You !"
SQLData.Close()
End Sub
Your problem is that you are opening a connection (SQLData), ignoring it, then trying to open a new connection (con) without giving it a connection string. Instead of this:
Dim con As New SqlConnection
Dim cmd As New SqlCommand
con.Open()
cmd.Connection = con
you should have:
Dim cmd As New SqlCommand
cmd.Connection = SQLData
Also, it is very bad practice to insert string value inline in SQL as you have.
I would recommend an approach something like this:
Protected Function Button1_Click(sender As Object, e As System.EventArgs)
' define and create your one single SqlConnection and protect it by using a "using()....." block
Using _connection As New SqlConnection("Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database.mdf;Integrated Security=True;User Instance=True")
' define and craete your SqlCommand to count your occurences and make it a proper, parametrized query
Using cmdSelect As New SqlCommand("SELECT COUNT(*) FROM dbo.Table1 WHERE Name = #Name", _connection)
' add the parameter to your SqlCommand, define the datatype and length
cmdSelect.Parameters.Add("#Name", SqlDbType.VarChar, 100)
' set the value for that parameter
cmdSelect.Parameters("#Name").Value = TextBox1.Text.Trim()
' open connection, execute query, set return value
_connection.Open()
If cmdSelect.ExecuteScalar() > 0 Then
Label1.Text = "You have already voted this service"
Return
End If
End Using
' define second query to insert data reusing the existing connection
Using cmdInsert As New SqlCommand("INSERT INTO dbo.Table1(Name) VALUES(#Name)", _connection)
' add the parameter to your SqlCommand, define the datatype and length
cmdInsert.Parameters.Add("#Name", SqlDbType.VarChar, 100)
' set the value for that parameter
cmdInsert.Parameters("#Name").Value = Label1.Text.Trim()
cmdInsert.ExecuteNonQuery()
End Using
_connection.Close()
End Using
Label1.Text = "Thank You !"
End Function
Points to consider:
you have one SqlConnection - that's good enough for both queries, reuse it!
always put your disposable objects like SqlConnection, SqlCommand into Using..... blocks to protect them and make sure they get properly disposed
always use parametrized queries - do NOT under any circumstances just concatenate together your SQL statements - that's a big huge gaping security hole, inviting SQL injection attacks - just DON'T do it - EVER!
if I could, I would try to separate your UI elements from the code - try to put this code into a separate method that will take in the string values from the caller, and will return a result string to be set on the UI (Label1.Text=). Mixing code that queries the database and setting the UI at the same time is messy and leads to spaghetti code - try to separate those things
put your connection string into the web.config into the <connectionStrings> section and read it from there - don't have your connection string as a string literal all throughout your code!
There's a few things I see wrong there. First, (other than the SQL injection vulnerability) is that you typed Table1 once, and Tabel1 the other time. While that could be what you want, I doubt it. Next you're creating a second connection. That doesn't seem to be needed. Use the existing SQLData object instead of con. You can also reduce the lines starting from the declaration of cmd (inclusive) to the ExecuteNonQuery call (exclusive) with this:
Dim cmd As New SqlCommand("INSERT INTO Tabel1 (Name) VALUES('" & Trim(Label1.Text) & "')", SQLData)
Now back to that SQL injection vulnerability. What if someone's name is "James O'Brian" (or something else with an apostrophe in it)?
Related
i am trying to get data from ms access database using this code but i can not this is my code is this correct
Dim query As String = "SELECT [data] FROM tabless WHERE user = '" & user.Text & "'"
Using connection As New OleDbConnection(connectionString)
Dim cmd As New OleDbCommand(query)
Dim adapter As OleDbDataAdapter = New OleDbDataAdapter(query, connection)
Dim com As New OleDbCommand(query, connection)
connection.Open()
'on the line below I get an error: connection property has not been initialized
Dim reader As OleDbDataReader = cmd.ExecuteReader()
While reader.Read()
Label1.Text = (reader(0).ToString())
End While
reader.Close()
End Using
Database
|data|
asl
trying to get data from database and trying to show it in a label is this possible
You never associated cmd with the connection, and you never use com or adapter. This is the sort of thing you can figure out by stepping through your code line by line and inspecting the state of it.
Dim query As String = "SELECT [data] FROM tabless WHERE user = '" & user.Text & "'"
Using connection As New OleDbConnection(connectionString)
Dim cmd As New OleDbCommand(query, connection)
connection.Open()
Dim reader As OleDbDataReader = cmd.ExecuteReader()
While reader.Read()
Label1.Text = (reader(0).ToString())
End While
reader.Close()
End Using
Also, your code is vulnerable to a SQL Injection Attack. You should not be concatenating strings together to form your queries. You should instead use parameterized queries.
So I have a label which shows the username of the user. I've used this value to return their ID which I then attach to a label. I used execute scalar to do this because I wasn't sure how else to get a single value on a label.
This works fine. I then use the ID from the label and put it in another table. I can do this twice and then the page crashes saying...
"Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression."
However I don't understand. I don't pull anything from the second table on the page. I don't know why it would affect it. I feel like I've tried everything. Taking out the line that posts the ID to the label lets the page run but I need it there.
Label2.Text = User.Identity.Name
Dim connetionString As String
Dim cnn As SqlConnection
Dim cmd As SqlCommand
Dim sql As String
connetionString = "Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\FYPMS_DB.mdf;Integrated Security=True"
sql = "SELECT SupID FROM Supervisor WHERE (Email = #Email)"
cnn = New SqlConnection(connetionString)
Try
cnn.Open()
cmd = New SqlCommand(sql, cnn)
cmd.Parameters.Add(New SqlParameter("#Email", User.Identity.Name))
Dim supid1 As Int32 = Convert.ToInt32(cmd.ExecuteScalar())
cmd.Dispose()
cnn.Close()
Label1.Text = supid1.ToString
Catch ex As Exception
MsgBox("Can not open connection ! ")
End Try
End Sub
This should return the first result for you. Also, it's a good idea to employ Using blocks for objects such as connections, commands, and readers.
Using cn = New SqlConnection("Data Source=(LocalDB)\v11.0;AttachDbFilename=|DataDirectory|\FYPMS_DB.mdf;Integrated Security=True")
cn.Open()
Using cmd = New SqlCommand("SELECT SupID FROM Supervisor WHERE Email = #Email", cn)
cmd.Parameters.AddWithValue("#Email", User.Identity.Name)
Using dr = cmd.ExecuteReader
If dr.Read Then
Label1.Text = CInt(dr("SupID"))
End If
End Using
End Using
End Using
If you are not sure there are multiple rows for same email in that table, you can change the query to following, that will work for you with executescalar.
SELECT TOP 1 SupID FROM Supervisor WHERE (Email = #Email)
Horribly sorry! But yes you were right! There was another query going on in the background that I never noticed that was affecting it all. So sorry
I receive the error
No value given for one or more required parameters
when I try to execute the following code
Protected Sub Button2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button2.Click
Dim t2 = TextBox2.Text
Dim dbcmd As OleDbCommand
dbcmd = New OleDbCommand("UPDATE login1 SET height ='" + TextBox2.Text + "' WHERE username =" + str, dbcon) //This is the part where the error is ....
dbcon.Open()
dbcmd.ExecuteNonQuery()
dbcon.Close()
End Sub
End Class
I've tried making changes in this statement like using different methods with parameters...but all the code shows the same error.
Using a parameterized query is definitely the way to go, but using named parameters should be discouraged in this context because OleDbCommand objects ignore the parameter names when the CommandType is Text. They only rely on the order in which the parameters appear in the CommandText (ref: here).
Therefore, the preferred approach would be
Using dbcmd As New OleDbCommand(
"UPDATE login1 SET height=? WHERE username=?",
dbcon)
dbcmd.Parameters.AddWithValue("?", TextBox2.Text) ' height
dbcmd.Parameters.AddWithValue("?", str) ' username
dbcmd.ExecuteNonQuery()
End Using
You don't supply the user name properly at the end of the query. But that's not the only problem here. Let me edit the code a bit:
Using dbcon As New OleDbConnection(cString)
dbcon.Open()
Using dbcmd As New OleDbCommand(
"UPDATE login1 SET height = #height WHERE username = #username",
dbcon)
dbcmd.Parameters.AddWithValue("#height", TextBox2.Text)
dbcmd.Parameters.AddWithValue("#username", str)
dbcmd.ExecuteNonQuery()
End Using
End Using
NOTE: the using statement to ensure the objects are disposed property and also, do not share connections. When you need a connection, build it, open it, use it, and dispose it.
I'm trying to update a record from an Ms-Access table with VB.NET and ASP.NET. I'm getting 2 errors:
On the web page that's opened I'm getting Thread was being aborted
Web Developer 2010 gives me an error says there's an error in the
UPDATE statement
This is the code so far:
Imports System.Data.OleDb
Partial Class ChangePassword
Inherits System.Web.UI.Page
Protected Sub btnChange_Click(sender As Object, e As System.EventArgs) Handles btnChange.Click
Dim tUserID As String = Session("UserID")
Dim conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Users\Brian\Documents\Visual Studio 2010\WebSites\WebSite3\db.mdb;")
conn.Open()
Dim cmd As OleDbCommand = New OleDbCommand("SELECT * FROM [User] where UserID=?", conn)
Dim cmd2 = New OleDbCommand("UPDATE USER SET [Password] = '" + txtConfPass.Text + "' where UserID = '" + tUserID + "'", conn)
cmd.Parameters.AddWithValue("#UserID", tUserID)
Dim read As OleDbDataReader = cmd.ExecuteReader()
Dim read2 As OleDbDataReader = cmd2.ExecuteReader()
lblUser.Text = tUserID.ToString
lblUser.Visible = True
If read.HasRows Then
While read.Read()
If txtOldPass.Text = read.Item("Password").ToString Then
cmd2.ExecuteNonQuery()
lblPass.Visible = True
End If
End While
Else
lblPass.Text = "Invalid Password."
lblPass.Visible = True
End If
conn.Close()
lblPass.Text = tUserID.ToString
lblPass.Visible = True
Any help would be appreciated.
Thanks !
First, your cmd2 fails because USER is a reserved word. Enclose in
square brackets as you already do in the first OleDbCommand.
Second, to execute a statement like UPDATE, INSERT, DELETE you call
cmd2.ExecuteNonQuery not ExecuteReader. Don't really needed that call
after the first for cmd.
Third, in the first OleDbCommand (cmd) you use a parameter for
UserID, why in the second one you revert to string concatenation for
user and password? This opens the door to any kind of Sql Injection
Attack.
Fourth, the Using statement assure that every Disposable object
used in your code will be CLOSED thus freeing the memory used by
this commands ALSO IN CASE OF EXCEPTIONS. An example of Using
statement here
(1)
Dim read2 As OleDbDataReader = cmd2.ExecuteReader()
and then
(2)
cmd2.ExecuteNonQuery()
Remove (1) - ExecuteNonQuery should do the update.
USER is a keyword in Access, add brackets the same way you have added in the Select statement. Next time, you are faced with a similar problem, print out the statement as Access would see it and try executing it on the database directly - that will point out the errors accurately.
Please use place holders for the update statement similar to the select statement.
I have this mySQL code that connects to my server. It connects just fine:
Dim MyConString As String = "DRIVER={MySQL ODBC 3.51 Driver};" & _
"SERVER=example.com;" & _
"DATABASE=xxx;" & _
"UID=xxx;" & _
"PASSWORD=xxx;" & _
"OPTION=3;"
Dim conn As OdbcConnection = New OdbcConnection(MyConString)
conn.Open()
Dim MyCommand As New OdbcCommand
MyCommand.Connection = conn
MyCommand.CommandText = "select * from userinfo WHERE emailAddress = '" & theUN & "'""
MyCommand.ExecuteNonQuery()
conn.Close()
However, i have an old Classic ASP page that uses "oRecordset" to get the data from the mySQL server:
Set oConnection = Server.CreateObject("ADODB.Connection")
Set oRecordset = Server.CreateObject("ADODB.Recordset")
oConnection.Open "DRIVER={MySQL ODBC 3.51 Driver}; SERVER=example.com; PORT=3306; DATABASE=xxx; USER=xxx; PASSWORD=xxx; OPTION=3;"
sqltemp = "select * from userinfo WHERE emailAddress = '" & theUN & "'"
oRecordset.Open sqltemp, oConnection,3,3
And i can use oRecordset as follows:
if oRecordset.EOF then....
or
strValue = oRecordset("Table_Name").value
or
oRecordset("Table_Name").value = "New Value"
oRecordset.update
etc...
However, for the life of me, i can not find any .net code that is similar to that of my Classic ASP page!!!!!
Any help would be great! :o)
David
This is what you have to do:
instead of MyCommand.ExecuteNonQuery you should use MyCommand.ExecuteQuery and assign it to DataReader.
Check out this sample:
Dim myConnection As SqlConnection
Dim myCommand As SqlCommand
Dim dr As New SqlDataReader()
'declaring the objects
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs)_
Handles MyBase.Load
myConnection = New SqlConnection("server=localhost;uid=sa;pwd=;database=pubs")
'establishing connection. you need to provide password for sql server
Try
myConnection.Open()
'opening the connection
myCommand = New SqlCommand("Select * from discounts", myConnection)
'executing the command and assigning it to connection
dr = myCommand.ExecuteReader()
While dr.Read()
'reading from the datareader
MessageBox.Show("discounttype" & dr(0).ToString())
MessageBox.Show("stor_id" & dr(1).ToString())
MessageBox.Show("lowqty" & dr(2).ToString())
MessageBox.Show("highqty" & dr(3).ToString())
MessageBox.Show("discount" & dr(4).ToString())
'displaying the data from the table
End While
dr.Close()
myConnection.Close()
Catch e As Exception
End Try
HTH
Dim conn As OdbcConnection = New OdbcConnection("DRIVER={MySQL ODBC 3.51 Driver}; SERVER=xxx.com; DATABASE=xxx; UID=xxx; PASSWORD=xxx; OPTION=3;")
conn.Open()
Dim MyCommand As New OdbcCommand
MyCommand.Connection = conn
MyCommand.CommandText = "SELECT * FROM userinfo"
Dim rst = MyCommand.ExecuteReader()
While rst.Read()
response.write(rst("userID").ToString())
End While
conn.Close()
Dim email As String = "anyone#anywhere.com"
Dim stringValue As String
Using conn As OdbcConnection = New OdbcConnection(MyConString)
conn.Open()
Dim sql = "Select ... From userInfo Where emailAddress = #Email"
Using cmd As OdbcCommand = New OdbcCommand(sql, conn)
cmd.Parameters.AddWithValue("#Email", email)
Dim reader As OdbcDataReader = cmd.ExecuteReader()
While reader.Read()
stringValue = reader.GetString(0)
End While
End Using
conn.Close()
End Using
'To do an Update
Using conn As OdbcConnection = New OdbcConnection(MyConString)
conn.Open()
Dim sql As String = "Update userInfo Set Column = #Value Where PK = #PK"
Using cmd As OdbcCommand = New OdbcCommand(sql, conn)
cmd.Parameters.AddWithValue("#Email", email)
cmd.ExecuteNonQuery()
End Using
End Using
'To do an Insert
Using conn As OdbcConnection = New OdbcConnection(MyConString)
conn.Open()
Dim sql As String = "Insert userInfo(Col1,Col2,...) Values(#Value1,#Value2...)"
Using cmd As OdbcCommand = New OdbcCommand(sql, conn)
cmd.Parameters.AddWithValue("#Col1", value1)
cmd.Parameters.AddWithValue("#Col2", value2)
...
cmd.ExecuteNonQuery()
End Using
End Using
First, even in ASP Classic, it is an absolutely horrid approach to concatenate a value directly into a SQL statement. This is how SQL Injection vulnerabilities happen. You should always sanitize values that get concatenated into SQL statements. In .NET, you can use parametrized queries where you replace the values that go into your query with a variable that begins with an # sign. You then add a parameter to the command object and set your value that way. The Command object will sanitize the value for you.
ADDITION
You mentioned in a comment that your ASP Classic code is shorter. In fact, the .NET code is shorter because there are a host of things happening that you do not see and have not implemented in your ASP Classic code. I already mentioned one which is sanitizing the inputs. Another is logging. Out of the box, if an exception is thrown, it will log it in the Event Log with a call stack. To even get a call stack in ASP Classic is a chore much less any sort of decent logging. You would need to set On Error Resume Next and check for err.number <> 0 after each line. In addition, without On Error Resume Next, if an error is thrown, you have no guarantee that the connection will be closed. It should be closed, but the only way to know for sure is to use On Error Resume Next and try to close it.
Generally, I encapsulate all of my data access code into a set of methods so that I can simply pass the SQL statement and the parameter values and ensure that it is called properly each time. (This holds true for ASP Classic too).