mysql connections

Posted by Lilbopeep on Mon 17 Aug 2009 03:05 AM — 26 posts, 109,362 views.

USA #0
hey everyone!

okay, so I have a server with mysql on it, but I'm having trouble getting any of the scripts work with it. I plan on creating a database to store multiple things, and use alias' to create queries / modifications to the different tables. The catch is I plan to create a plug-in so other people can access and possibly modify. From there, I hope to move the output into a miniwindow, but plan on just noting it into the output for now.

I don't know one scripting language from the other, but with an example I can generally figure out what's happening - so to that end I am open to using any one of the many scripting languages to build this.

For starters..

What do I need to do first? Many of the database plug-ins or scripts require additional dll's, but I don't know if anything has changed with my version (4.43).

From there, How do I connect to my database? Let's say I have a database called test with a table called areas and fields name level directions... see where I am going?

Simple is best, for me, and any help is appreciated! thanks!
#1
Try these:
http://www.gammon.com.au/forum/?id=9262&page=999
http://www.gammon.com.au/forum/?id=9650&page=999
USA #2
Oh, that's going to be very helpful once I figure out how to connect to my database, thank you!
#3
This one might help.
http://www.gammon.com.au/forum/?id=5983

I used the info above to make a plugin that connects to a public database on the internet.

    assert (package.loadlib ("mysql.dll", "luaopen_luasql_mysql")) ()

    env = assert (luasql.mysql())
    
    con = assert (env:connect ("adatabase", "guest", "password", "adatabase.org"))
USA #4
To be honest, I don't think it's a good idea to access your database directly like this, it opens up a lot of ways for people to do malicious stuff. What I'd do is get the LuaSocket library (which Nick mentioned once or twice he might be adding to MUSHclient anyways), and use its HTTP protocol extension to send GET/POST messages to the server. The server can then take some action (verify incoming data for one) and return a proper response.
Australia Forum Administrator #5
The other question is, is this for you alone? Then SQLite might be easier, and you just have a disk file on your disk. See my recent posts about http://mushclient.com/sql and http://mushclient.com/db.

As for the malicious stuff, he has a point, but with user access control it might be reasonably safe. And you could consider adding referential integrity checks to the database.
USA #6
Malicious how? Only people I "trust" would be given credentials to log in and access information. It wouldn't be a public database.

A secondary benefit is the potential to do similar things with a database through the website, and from what i've seen php and mysql seem to be the de facto way to handle this, so it's perfect for me, unless I am missing something crucial?
Australia Forum Administrator #7
No, you're fine. The post Blainer mentioned at http://www.gammon.com.au/forum/?id=5983 should help you.

If something goes wrong, please be specific about what it is. For example, the database might need 'grant' access to give you remote access.

Something like (in SQL):


GRANT ALL ON your_database.* TO Lilbopeep@wherever_you_are IDENTIFIED BY "yourpassword";

USA #8
okay, well my first option was just to try to load the DLL. Seemed simple enough -

[string "Alias: "]:2: Function 'package.loadlib' disabled in Lua sandbox - see MUSHclient global preferences
stack traceback:
	[C]: in function 'error'
	[string "Sandbox"]:39: in function 'loadlib'
	[string "Alias: "]:2: in main chunk


So I checked global preferences, saw a little box that said 'allow DLL's to be loaded' and figured that was my issue, but checking said box didn't work, I still got the same error.

my alias is simply -

-- load the MySQL dll
assert (package.loadlib ("mysql.dll", "luaopen_luasqlmysql")) ()


with send to Script selected.
USA #9
IF you're going to be doing stuff with a database, you definitely want to start using the script file and not just trigger's send to boxes...

Also, in Lua 5.1, loadlib is deprecated. If you have luasql downloaded, you can just

require "luasql.mysql"


Installing luasql is as simple as downloading it, and then setting a variable to point to the directory. Press the Windows key + Pause (it's in the top right corner) go to the advanced tab, click environment variables, and add a system variable for:

LUA_CPATH=.\?.dll;C:\Lua\5.1\clibs\?.dll;C:\path\to\dled\file\?.dll


So if you wanted, you could make a subdirectory under Mushclient's LUA directory named luasql, and put the mysql.dll in there...

LUA_CPATH=.\?.dll;C:\Lua\5.1\clibs\?.dll;C:\program files\mushclient\lua\?.dll;


Restart Mushclient, press CTRL+SHIFT+H to bring up the script file (it will yell at you to set one up if you haven't) and require away...

USA #10
well, I'm not opposed to going with something like this, but honestly it doesn't make any sense :(

I mean, it seems like -another- way to do it, but none of these links have gotten me past step 1, despite following them almost exactly. Moving something to a script file seems secondary to just getting /some/ progress, and I'll get back to it later.

I don't even know what luasql.mysql is. In my MUSHclient folder I have lua5.1.dll, libmysql.dll, and mysql.dll. I believe I added the last two myself from instructions on another page.

I've done this easily with PHP before -

<?php
$dbhost = 'localhost';
$dbuser = 'username';
$dbpass = 'password';

$conn = mysql_connect($dbhost, $dbuser, $dbpass) or die ('Error connecting to mysql');

$dbname = 'test';
mysql_select_db($dbname);
?>


Is it this much more difficult? Is PHPscript the same as PHP?
USA #11
Step By Step:

1. Download LUASQL from the kepler project:
http://luaforge.net/frs/download.php/2683/luasql-2.1.1-mysql50-win32-lua51.zip
PHP was designed for dynamic webpage generation, it was assumed you'll be talking to a database so it's built in. I guarantee you'll have an easier time getting MC to talk to MySql than you will getting PHP/Apache to handle telnet negotiation. :)

2. Extract that zip to C:\Program Files\Mushclient\Lua. There should now be a C:\Program Files\Mushclient\Lua\Luasql\MySql.dll (you can probably move the one you already got to that directory)

3. Press Ctrl+Alt+G and make sure you can load dll's (you have already done this.)

4. Press CTRL+SHIFT+6 and configure Mushclient to have a script file. I'm assuming you're leaving the scripting language as Lua, and you can put the script file where ever you like. (My Documents?). Click OK.

5. Press CTRL+SHIFT+H (Game menu -> Edit Script File...) and start coding!

6. for example:
 
require "luasql.mysql"
sourcename = "something to connect to my database"
username = "me"
password = "swordfish"
hostname = "mysql.internet.org"
port = "4314"

env = luasql.mysql()
db = env:connect(sourcename, username, password, hostname, port)
cursor = db:execute("SELECT theanswer FROM mybutt")


7. read http://www.keplerproject.org/luasql/manual.html for more information on working with Luasql.




It's not that difficult, but you're biting off a rather large chunk for someone that "doesn't know one scripting language from another".
Australia Forum Administrator #12
Quote:

So I checked global preferences, saw a little box that said 'allow DLL's to be loaded' and figured that was my issue, but checking said box didn't work, I still got the same error.


Slow down a minute. You are on the right track here.

After checking that box you need to reload the script file to get the new sandbox processed.

Just closing the world and re-opening it will do that, but there is a menu item as well.

It *does* work. :)
USA #13
Quote:

Slow down a minute. You are on the right track here.

After checking that box you need to reload the script file to get the new sandbox processed.

Just closing the world and re-opening it will do that, but there is a menu item as well.

It *does* work. :)


But it doesn't. The box is clearly checked. I've gone as far as closing / reopening the world to closing and opening MUSHclient itself.

I have an alias that is


-- load the MySQL dll
assert (package.loadlib ("mysql.dll", "luaopen_luasqlmysql")) ()


and when I type the alias I get the same message


[string "Alias: "]:2: Function 'package.loadlib' disabled in Lua sandbox - see MUSHclient global preferences
stack traceback:
	[C]: in function 'error'
	[string "Sandbox"]:39: in function 'loadlib'
	[string "Alias: "]:2: in main chunk


I mean, if we ignored everything else I wanted to do and started off with the proverbial baby-step, this seems to be the first one; including the mysql.dll file.

And thanks for all the responses, btw! Such a lovely client.
Amended on Mon 17 Aug 2009 08:35 AM by Lilbopeep
USA #14
You need to trust both the world and whatever plugin you're putting it in (if any). For the former, use ctrl+I and run "print(GetWorldID())" to get your world's ID. For the latter, it's in the plugin's XML near the top.

To add these to the trusted list, go to File -> Global Preferences and hit the Lua tab. Look for a line that starts with "local trusted_worlds = {", and add a new line with your world ID. I'll paste an example below. Do the same for your plugin (if any), but in the "local trusted_plugins" table.


  local trusted_worlds = {
 --  ["a4a1cc1801787ba88cd84f3a"] = true,  --example world
     ["your world ID here"] = true
      }  -- end of trusted_worlds 

  -- Plugin IDs of plugins we trust - add your plugins to the table

  local trusted_plugins = {
 --  ["03ca99c4e98d2a3e6d655c7d"] = "Chat", --example plugin
     ["your plugin ID here"] = true
     }  -- end of trusted_plugins 


It's annoying and I've posted about it elsewhere, I'm glad I'm not the only one who got caught by it. (EDIT: I mean the fact that you have to trust the plugin AND the world to get a plugin to work properly. Never mind that it's an annoying process to look for and add the entry/entries in the first place...)
Amended on Mon 17 Aug 2009 08:35 AM by Twisol
USA #15
Easily done. But it still spits errors. Check on that line number it gave me there is this function



function MakeSandbox ()

  local function ReportDisabled (pkg, func)
     return function ()
       error (string.format (
        "Function '%s.%s' disabled in Lua sandbox - see MUSHclient global preferences",
        pkg, func), 2)
       end -- function
  end -- ReportDisabled 

  package.loadlib = ReportDisabled  ("package", "loadlib") -- disable loadlib function
  package.loaders [3] = nil  -- disable DLL loader
  package.loaders [4] = nil  -- disable all-in-one loader

  for k, v in pairs (io) do
    if type (v) == "function" then
      io [k] = ReportDisabled ("io", k)
    end -- type is function
  end -- for



So.. you check the box, add the world.. and do something else? If it was false I would just flick it over to true, but i have no idea what to do about this nil business.
Australia Forum Administrator #16
Here is how I got it to work on a new MUSHclient installation:



Now, this works in my Immediate window:


 assert (package.loadlib ("mysql.dll", "luaopen_luasqlmysql")) ()

 env = assert (luasql.mysql())
    
 con = assert (env:connect ("databasename", "username", "password", "site_address"))

 -- retrieve a cursor
 cur = assert (con:execute ("SELECT count(*) from some_table" ))

 -- print all rows, the rows will be indexed by field names
 row = cur:fetch ({}, "a")

 while row do
   table.foreach (row, print)
   row = cur:fetch (row, "a")
 end

 -- close everything
 cur:close()
 con:close() 
 env:close()


Australia Forum Administrator #17
Quote:

And thanks for all the responses, btw! Such a lovely client.


*blush*
USA #18
Hot skippy peanut butter.


With a little fiddling I am able to connect to my other computer and run queries on tables. Hurray for progress!!

You guys are awesome!

It was able to count my 6 records no problem!

USA #19
So now that I have a connection, I've been playing around with a few of the simple databases I have. What I am really trying to figure out now is how to call specific records through aliases and also how to format them. As an example, my current script looks very similar to the one provided -



cur = assert (con:execute"SELECT * from race_pc")
-- print all rows, the rows will be indexed by field names
row = cur:fetch ({}, "a")
while row do
  print(string.format("Name: %s, Remort: %s", row.Name, row.Remort))
  -- reusing the table of results
  row = cur:fetch (row, "a")
end


This gives me the basic output of:

Name: Human1, Remort: Non-Remort
Name: Dwarf, Remort: Non-Remort
Name: Elf, Remort: Non-Remort
Name: Firbolg, Remort: Non-Remort
Name: Big Dwarf, Remort: 1st-Remort
Name: Bigger Dwarf, Remort: 2nd-Remort

However, I have more information than this in my databases, it just doesn't "look" very pretty like this, and it is calling every entry, which is fine right now, but I may like to get more selective in the future.

The additional columns I have are 10 'stat' entries with positive and negative values as racial bonuses, which language they speak, what size they are, and the skills they start with.

How do I make all this information look a little 'neater' on the output? For instance

Name: <show name> Remort: <show remort>
Size: <show size> Language: <how language>
Skills: <show skills>
 St   Qu   Pr   Em   In   Co   Ag   Sd   Me   Re
<st> <qu> <pr> <em> <in> <co> <ag> <sd> <me> <re>


And I also need some help figuring out how to query based on wildcards. Lets say I had an alias 'lookup race *' and it would pull the record or records that match? I was thinking I would have to somehow store whatever was given as a variable and put that into the select statement?
Amended on Tue 18 Aug 2009 06:46 AM by Lilbopeep
Australia Forum Administrator #20
The neater formatting is just the judicial use of string.format. For example:


print (string.format ("%-3s %-3s %-3s", "a1", "b", "c")) --> Outputs: a1  b   c  


Note that each entry takes 3 spaces, left justified.

Quote:

I also need some help figuring out how to query based on wildcards


Just add a WHERE clause to the SELECT, like this:


race = "dwarf"  -- for example

cur = assert (con:execute (string.format ("SELECT * from race_pc WHERE race = '%s' ", race))
Amended on Tue 18 Aug 2009 06:59 AM by Nick Gammon
USA #21

local charOutput =[[Name: %s Remort: %s
Size: %s Language: %s
Skills: %s
 St   Qu   Pr   Em   In   Co   Ag   Sd   Me   Re
 %s   %s   %s   %s   %s   %s   %s   %s   %s   %s
]]
cur = assert (con:execute(string.format("SELECT * FROM race_pc WHERE %s LIKE '%%%s%%'", ColumnVarSetbyAlias, FilterVarSetbyAlias)
-- print all rows, the rows will be indexed by field names

local row = {}

while cur:fetch (row, "a") do
  print(string.format(charOutput, row.Name, row.Remort, row.Size, 
			row.Language, row.Skills, row.St, row.Qu, row.Pr, 
			row.Em, row["In"], row.Co, row.Ag, row.Sd, row.Me, row.Re))
end

cur:close()



SQL (MySql, SQLite, MS SQL Server, Oracle, yadda yadda) use % as a wildcard, the "like" keyword means a pattern search. Since string.format uses % for special characters as well, you need to double them up if you want a literal % character. So, if ColumnVarSetbyAlias is "language", and FilterVarSetbyAlias is "orc" then the format function becomes "...WHERE language LIKE '%orc%'" which will give you a match anywhere the string orc is in that field. http://www.mushclient.com/scripting has a walkthrough with screenshots (though the shreenshots are for a really old version of MC) if you have questions on setting up an alias.

Lua uses [[ ]] for long strings.

foo = "This produces
errors." -- since Lua wants the close quote on the same line.

bar = [[This doesn't
produce errors, since lua will put everything into the variable upto the ]]


USA #22
Ah. I think I got the basics of using that string.format. Thanks Nick!


I'm still a little lost on the wildcards -

Say for instance I wanted to be able to look up race information based on the master race, I would provide this when I typed the alias like:

lookup Dwarves

and this would essentially do

"SELECT * FROM race_PC WHERE Race = Dwarves"

Your example also added (string.format to the mysql query, which my script currently does not. It currently looks like:


ur = assert (con:execute("SELECT * from race_pc"))
-- print all rows, the rows will be indexed by field names
row = cur:fetch ({}, "a")
while row do
  print(string.format("Master Race: %-3s", row.Race))
  print(string.format("Name: %-3s Remort: %-3s Size: %-3s", row.Name, row.Remort, row.Size))
  print(string.format("Creation Cost: %-3s", row.Creation_Cost))
  print("St Qu Pr Em In Co Ag Sd Me Re")
  print(string.format("%s, %s, %s, %s, %s, %s, %s, %s, %s, %s", row.Strength, row.Quickness, row.Presence, row.Empathy, row.Intuition, row.Constitution, row.Agility, row.Self_Discipline, row.Memory, row.Reasoning))
  -- reusing the table of results
  row = cur:fetch (row, "a")
end



Edit: Just saw WillFA's post, will give that a good read and see if I can get anywhere!
Amended on Tue 18 Aug 2009 07:35 AM by Lilbopeep
Australia Forum Administrator #23
Quote:

and this would essentially do

"SELECT * FROM race_PC WHERE Race = Dwarves"


For a start, you need to quote strings, so that should be:


"SELECT * FROM race_PC WHERE Race = 'Dwarves'  "


Then, as Willfa said, to get wildcards (if you want them) you can do LIKE:


"SELECT * FROM race_PC WHERE Race LIKE '%Dwarves%'  "


You still need the quotes. And he is right about the % symbols inside string.format.

USA #24
Hmm. I tried WillFa's way and its giving me


[string "Alias: "]:14: bad argument #2 to 'format' (string expected, got nil)
stack traceback:
	[C]: in function 'format'
	[string "Alias: "]:14: in main chunk


which is line

cur = assert (con:execute(string.format("SELECT * FROM race_pc WHERE %s LIKE '%%%s%%'", ColumnVarSetbyAlias, FilterVarSetbyAlias)))



At first I was getting some 'expected ")" to close yada' on that line, so I added two ")" at the end.

I also am not sure what my alias is supposed to look like. From the link provided, I would guess I need to focus on the information provided within the 'target' example of setting up an alias?
Australia Forum Administrator #25
Well, argument #2 is ColumnVarSetbyAlias.

Since you haven't quoted it, that is a variable. Does it contain a string? Sounds like not.