Uploading images to database using the BLOB throwing exception - mysql

I've been attempting to adapt part of this procedure that I found online (can't remember where now!). I've been trying to use this to upload images to a MYSQL database using BLOB data type.
Public Sub SQLUpload()
Dim connection As New MySqlConnection(ConnectionImage)
Dim command As New MySqlCommand("INSERT INTO Images (File, FileName, FileSize) VALUES (#Picture, 'Name1', 'Size1')", connection)
'Create an Image object.'
Using picture As Image = Image.FromFile("C:\DIR\Pictures\Person.jpg")
'Create an empty stream in memory.'
Using stream As New IO.MemoryStream
'Fill the stream with the binary data from the Image.'
picture.Save(Stream, Imaging.ImageFormat.Jpeg)
'Get an array of Bytes from the stream and assign to the parameter.'
command.Parameters.AddWithValue("#Picture", SqlDbType.VarBinary).Value = stream.GetBuffer()
End Using
End Using
connection.Open()
Try
command.ExecuteNonQuery()
Catch ex As Exception
MsgBox(ex.ToString)
End Try
connection.Close()
End Sub
Above is the current sub routine. Whenever this is executed, the routine operates fine until it gets to:
Command.ExecuteNonQuery()
It throws the error:
Unable to cast object of type System.Byte[] to type System.IConvertible
I'm pretty sure this happens because of the fact that the bytes from the image are returned as an array however the memory that they are saved to does not support an array? This was just gathered from reading I've done elsewhere online.
However, as this is not all my code I am frankly not sure what the problem is. Can anyone see what is wrong with it?
Many Thanks

Where you have
SqlDbType.VarBinary ' <-- this is Sql Server DB type
use
MySqlDbType.Blob
Like this
Dim file() As Byte = ' set your file
Dim p As MySqlParameter = new MySqlParameter("#Picture", MySqlDbType.Blob, file.Length)
p.Value = file
command.Parameters.Add(p)
As it mentioned by others, you don't need to "Save" your file - just read it into byte array. My code would look something like below:
Public Sub SQLUpload()
Try
Using conn As New MySqlConnection(connString)
' Parametarize entire sql string
Dim sql As String =
"INSERT INTO Images (File, FileName, FileSize) VALUES (#Picture, #name, #size)"
Using cmd As New MySqlCommand(sql, conn)
Dim fileName As String = "C:\DIR\Pictures\Person.jpg"
Dim file() As Byte = File.ReadAllBytes(fileName)
cmd.Parameters.AddWithValue("#Picture", MySqlDbType.Blob).Value = file
cmd.Parameters.AddWithValue("#file", MySqlDbType.VarChar).Value = fileName
cmd.Parameters.AddWithValue("#size", MySqlDbType.Int32).Value = file.Length
conn.Open()
cmd.ExecuteNonQuery()
End Using
End Using
MessageBox.Show("Success")
Catch ex As Exception
MessageBox.Show(ex.ToString())
End Try
End Sub

Related

how to save a byte() to my SQLDatabase using VB.net

I know that there are already a couple of questions which seems like my problem but I tried to copy a lot of it and tried but can’t get the resold I want.
Actually is my target to save an image from a Picture Box as Byte() into mySQL Database.
At first I tried the simple way like
Dim acCust As Image = pgbox.image
Dim picBytes() As Byte
Using ms As New MemoryStream
cust.Save(ms, cust.RawFormat)
picBytes = ms.ToArray()
End Using
but with this I run into a general GUI error so I copied the Picture at first like this
Dim rec As New Rectangle(0, 0, acCust.Width, acCust.Height)
Dim mus As New ImageFormatConverter
Dim muster As New Bitmap(rec.Width, rec.Height)
Dim cust As Image
Using grp = Graphics.FromImage(muster)
grp.DrawImage(acCust, New Rectangle(0, 0, rec.Width, rec.Height), rec, GraphicsUnit.Pixel)
cust = muster
End Using
If I use after that again the code
Dim picBytes() As Byte
Using ms As New MemoryStream
cust.Save(ms, cust.RawFormat)
picBytes = ms.ToArray()
End Using
sqlconection.Open()
Dim query As String = "INSERT INTO tblimg(img) VALUES ('#image');"
Dim com As New MySqlCommand(query, sqlconection)
com.Parameters.AddWithValue("image", picBytes)
com.ExecuteNonQuery()
sqlconection.Close()
everything looks sofa ok but if I read it like this
Dim imgData As Byte()
Dim sql As String = "SELECT img FROM tblimg"
sqlconection.Open()
Dim cmd As New MySqlCommand(sql, sqlconection)
Using rdr As MySqlDataReader = cmd.ExecuteReader
If rdr.HasRows Then
rdr.Read()
imgData = TryCast(rdr.Item("img"), Byte())
' in case this record has no image
If imgData IsNot Nothing Then
' ToDo: dispose of any previous Image
' create memstream from bytes
Using ms As New MemoryStream(imgData)
' create image from stream, assign to PicBox
pbbox.Image = CType(Image.FromStream(ms), Image)
End Using
End If
End If
End Using
I got an alarm message
Eine nicht behandelte Ausnahme des Typs "System.ArgumentException" ist in System.Drawing.dll aufgetreten.
Zusätzliche Informationen: Ungültiger Parameter.
(Sorry it's in German)
Has anybody an idea what and were it’s going wrong?
If I use the the picByts () in a new memory stream and convert it back to an image then I got the correct result. It seems like there is a problem with the up or download query
in my Server I use the variable type LongBlob
You save a Byte array to a database in exactly the same way as you save any other data. You write your SQL, you add a parameter to a command and you set its value. This:
Dim query As String = "INSERT INTO tblimg(img) VALUES ('#image');"
Dim com As New MySqlCommand(query, sqlconection)
com.Parameters.AddWithValue("image", picBytes)
is wrong. You only wrap literal strings in single quotes in SQL code. That should be like this:
Dim query As String = "INSERT INTO tblimg(img) VALUES (#image);"
Dim com As New MySqlCommand(query, sqlconection)
com.Parameters.AddWithValue("#image", picBytes)
No single quotes around the parameter in the SQL and use the actual parameter name when adding it to the command. I'd also recommend using Add rather than AddWithValue but that's a discussion for another time.

Parameterize SQL Queries

I want parameterize some SQL Statements so my code isn't vunerable to SQL Injections any longer But i have actually no plan how to parameterize for example a where clause.
Dim accID As String = DatabaseConnecter.readField("SELECT ID FROM accounts WHERE accountname ='" & user & "' AND password='" & pw & "';")
The Problem is if you type in a given username, for example test and extend the username with. You can log in without entering the password into the Application.
Edit:
Public Function readField(ByVal sql As String) As String
Dim output As String = "ERROR"
Using cn = New MySqlConnection(connString.ToString())
Using cmd = New MySqlCommand(sql, cn)
cn.Open()
Using rd = cmd.ExecuteReader()
Try
rd.Read()
output = rd.GetString(0)
rd.Close()
Catch ex As Exception
End Try
End Using
cn.Close()
End Using
End Using
Return output
End Function
´´´
To have a parameterized query you need to create parameters and write a proper SQL text where, in place of values typed directly from your user, you have parameter placeholders.
So, for example, you sql text should be something like this
Dim sqlText = "SELECT ID FROM accounts WHERE accountname =#name AND password=#pwd"
Now you have a parameterized text, but stil we need to create the parameters that will be sent to the database engine together with your sql command.
You can create the parameter (two in this case) in this way before calling the method that executes the query
Dim p1 as MySqlParameter = new MySqlParameter("#name", MySqlDbType.VarChar)
p1.Value = user
Dim p2 as MySqlParameter = new MySqlParameter("#pwd", MySqlDbType.VarChar)
p2.Value = password
Dim pms As List(Of MySqlParameter) = new List(Of MySqlParameter)()
pms.Add(p1)
pms.Add(p2)
Now we need to pass this list to your method (and this requires changes to your method signature)
DatabaseConnecter.readField(sqlText, pms)
The method itself should change to something like
Public Function readField(ByVal sql As String, Optional pms As List(Of MySqlParameter) = Nothing) As String
Dim output As String = "ERROR"
Using cn = New MySqlConnection(connString.ToString())
Using cmd = New MySqlCommand(sql, cn)
cn.Open()
' This block adds the parameter defined by the caller to the command
' The parameters are optional so we need to check if we have really received the list or not
if pms IsNot Nothing Then
cmd.Parameters.AddRange(pms.ToArray())
End If
Using rd = cmd.ExecuteReader()
Try
rd.Read()
output = rd.GetString(0)
rd.Close()
Catch ex As Exception
End Try
End Using
' no need to close when inside a using block
' cn.Close()
End Using
End Using
Return output
End Function
The method now has an optional parameter that will contain the list of the parameters required by the query (or nothing if your query doesn't require parameters). This list is added to the command parameters collection and the query is now executed.
Final Note: Storing passwords in clear text into a database is a well known security problem. I suggest you to search about how to store passwords in a database.
Private Function GetID(User As String, pw As String) As String
Using cmd As New SqlCommand("SELECT ID FROM accounts WHERE accountname =#user AND password=#password", New SqlConnection(SQLConnString))
cmd.Parameters.AddWithValue("#user", User)
cmd.Parameters.Add("#password", SqlDbType.NVarChar)
cmd.Parameters("#password").Value = pw
Try
cmd.Connection.Open()
Return cmd.ExecuteScalar()
Catch ex As Exception
'handle error
Return Nothing
Finally
cmd.Connection.Close()
End Try
End Using
End Function
I've demostrated two methods of setting the parameters. Search for more info or comparison.

Inserting PDF files into MYSQL with BLOB using VB.NET

I have been trying to figure out how to submit PDF files into a MYSQL database via my VB.NET project, so far I have only been able to figure out how to insert image files into the MYSQL but I'm not sure how to translate this code to support PDF files rather than images.
The code below shows how to browse an image and display it.
Try
Dim OFD As FileDialog = New OpenFileDialog()
OFD.Filter = "Image File (*.jpg;*.bmp;*.gif)|*.jpg;*.bmp;*.gif"
If OFD.ShowDialog() = DialogResult.OK Then
imgpath = OFD.FileName
PictureBox1.ImageLocation = imgpath
End If
OFD = Nothing
Catch ex As Exception
MsgBox(ex.Message.ToString())
End Try
The code below this shows the insertion of the image files into the MYSQL database once an image has been chosen.
Try
Dim mstream As New System.IO.MemoryStream()
PictureBox1.Image.Save(mstream, System.Drawing.Imaging.ImageFormat.Jpeg)
arrImage = mstream.GetBuffer()
Dim FileSize As UInt32
FileSize = mstream.Length
mstream.Close()
conn.ConnectionString = Myconnection
conn.Open()
sql = "insert into studentsubmissions(content, submissionid, studentnumber, time, date, deadline, title, work, modulename) VALUES (#filestuff, #subid, #stunumber, #subtime, #subdate, #workdeadline, #stutitle, #stuwork, #workmodulename)"
cmd.Connection = conn
cmd.CommandText = sql
cmd.Parameters.AddWithValue("#filestuff", arrImage)
cmd.Parameters.AddWithValue("#subid", idbox.Text)
cmd.Parameters.AddWithValue("#stunumber", usernameconstant.Text)
cmd.Parameters.AddWithValue("#subtime", todaystime.Text)
cmd.Parameters.AddWithValue("#subdate", todaysdate.Text)
cmd.Parameters.AddWithValue("#workdeadline", deadlinesubmission.Text)
cmd.Parameters.AddWithValue("#stutitle", titlesubmission.Text)
cmd.Parameters.AddWithValue("#stuwork", workload.Text)
cmd.Parameters.AddWithValue("#workmodulename", modulename.Text)
cmd.ExecuteNonQuery()
MessageBox.Show("Created")
cmd.Parameters.Clear()
conn.Close()
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
Below this is the method of displaying a PDF file on an Adobe PDF Reader in my project which is what I eventually want replacing the first set of code in displaying the documents and making the second set of code shown to support this.
Dim opf As New OpenFileDialog
opf.Filter = "PDF File | *.pdf"
If opf.ShowDialog = DialogResult.OK Then
AxAcroPDF1.src = opf.FileName
text_file.Text = opf.SafeFileName
End If

Show image using function

I'm new to VB. NET so please bear with me. In the code below, I have a picture box in my main form and I want the selected query profile_picture to show in the picture box but I have no idea what the function should return
Public Sub ShowPicture(ByVal username As String)
user = username
Dim dsSearch As DataSet
ModuleQuery.Showpic(username)
Dim dSearch As Byte() = DirectCast(dr("Photo"), Byte())
Dim ms As New MemoryStream(dsSearch)
prof_pic.Image = Image.FromStream(ms)
End Sub
This is a module which includes all SELECT queries so that it won't be messy.
I want to call a function but I don't know what to return so that I can show the image
Public Function Showpic(ByVal user As String)
Dim FunctionErrorState As Boolean = False
Dim InsertError As Boolean = False
Dim CloseError As Boolean = False
Dim dsData As New DataSet
Dim bite As Byte()
Try
openDB()
'MyADOConnection.Open()
Dim myQuery As String = "SELECT profile_picture FROM coa.register WHERE username = '" & user & "'"
Dim myCommand As New MySql.Data.MySqlClient.MySqlCommand(myQuery)
dr = myCommand.ExecuteReader
bite = DirectCast(dr("Photo"), Byte())
Catch ex As MySql.Data.MySqlClient.MySqlException
InsertError = True
End Try
Try
MyADOConnection.Close()
Catch exclose As MySql.Data.MySqlClient.MySqlException
CloseError = True
End Try
If InsertError Then
FunctionErrorState = True
End If
Return bite 'I just put something random here since I don't know what to retun
End Function
It looks to me like the image is being stored as a byte array in the database. You (i guess correctly) read this array from the database with the command bite = DirectCast(dr("Photo"), Byte()) in your ShowPic function. A byte array is just a large blob of data in memory, that you later query with the MemoryStream.
Therefore your ShowPic function (which is more a GetPic function ;-) should return Byte()
Public Function Showpic(ByVal user As String) As Byte()
You should initialize bite with Nothing
Dim bite As Byte() = Nothing
That way if an error occurs, the array will be nothing and you can check for that.
In order to convert the byte array, that contains the raw image data into an image you correctly use a MemoryStream and the Image.FromStream method. I/O in .NET works in large portions with streams. They are just a way to continously feed data from some source. In this case the source is just the memory, in particular the Byte array you got from the database.
You however never use that Byte array. Assign the result of the ShowPic function to a variable, in order to use it:
Public Sub ShowPicture(ByVal username As String)
user = username
Dim ImageData As Byte() = ModuleQuery.Showpic(username)
If ImageData IsNot Nothing Then
Using ms As New MemoryStream(ImageData)
prof_pic.Image = Image.FromStream(ms)
End Using
Else
'Your function returned nothing, so an error occured.
'This is a very crude way of error handling, since you never
'see the error in the first place, which makes debugging a
'nightmare. There are better ways, out of scope of this answer.
MessageBox.Show("No image retrieved due to an error :(")
End If
End Sub
That way you retrieve the image data from the database (again, rename it to GetPic or GetImageData or something) in ShowPic and return its raw data to the ShowPicture method where you decode and show it.

MySqlDataReader not returning data

As part of a project to import data into wordpress via screen scraping I've a database table of old and new URL's stored in a MySQL database. In the example below the ExecuteReader command doesn't appear to be returning any data (-1 rows effected), I've ran the SQL via workbench and that returns data, so it's not the SQL or data in the database.
At other times within the code I've called ExecuteNonQuery() and ExecuteScalar() both without issue (so it isn't the connection string).
Any ideas what to try next?
Dim SQL As String
Dim conn As MySqlConnection = New MySqlConnection(_CONNECTIONSTRING)
SQL = "SELECT OrgURL, NewURL FROM `wp_user`.`tbl_linkdata`"
Try
conn.Open()
Dim cmd As MySqlCommand = New MySqlCommand(SQL, conn)
Dim dr As MySqlDataReader = cmd.ExecuteReader()
While (dr.Read)
LinkHashMap.Add(dr.GetString(0), dr.GetString(1))
End While
Console.ForegroundColor = ConsoleColor.Cyan
Console.WriteLine("The Hash map contains " + dr.RecordsAffected + " rows")
dr.Close()
Catch ex As Exception
Console.ForegroundColor = ConsoleColor.Red
Console.WriteLine("Exception loading the hashtable : " + ex.Message)
Finally
conn.Dispose()
End Try
DataReader.RecordsAffected always returns -1 for a SELECT command. What does LinkHashMap.Count return? In MySqlDataReader it is the same:
"The number of rows changed, inserted, or deleted. -1 for SELECT
statements"
If you want to count the number of records you can use LinkHashMap.Count.
You: "LinkHashMap is "Nothing" "
How do you want to add something to it without initializing it first? A NullReferenceException should have happened. So initialize the dictionary (or whatever it is) first via constructor:
Dim LinkHashMap As New Dictionary(Of String, String)
While (dr.Read)
LinkHashMap.Add(dr.GetString(0), dr.GetString(1))
End While