PureBasic Forums — English
In this hard time, we have some of time for coding. Found here a module for make a customizable table with purebasic.
Version 1.1 beta 1
- Install git HERE
- make a right click on a directory and choice «Git Bash here»
- In the Git terminal paste this command «git clone https://github.com/microdevweb/PB_TABLE»
- Open the subdirectory «PB_TABLE» and run «example1.pb «
- Make a right click on the directory PB_TABLE and choice «Git Bash here»
- Use the command «git pull»
- And choise the last branch with «git checkout version.1.1»
Code of the example
Use Pb 5.73 lst and Windows 10
my mother-language isn’t english, in advance excuse my mistakes.
Как сделать таблицу в purebasic
In this hard time, we have some of time for coding. Found here a module for make a customizable table with purebasic.
Version 1.1 beta 1

- Install git HERE
- make a right click on a directory and choice «Git Bash here»
- In the Git terminal paste this command «git clone https://github.com/microdevweb/PB_TABLE»
- Open the subdirectory «PB_TABLE» and run «example1.pb «
- Make a right click on the directory PB_TABLE and choice «Git Bash here»
- Use the command «git pull»
- And choise the last branch with «git checkout version.1.1»
Code of the example
Use Pb 5.73 lst and Windows 10
my mother-language isn’t english, in advance excuse my mistakes.
Как сделать таблицу в purebasic
13.1 As I go. again
Welcome to my totally unstructured approach to databases, and may I end up where I want to be. (If I only knew where that would be :-)) I’m going to talk about SQLite and MySQL.
- Creating tables
- Adding columns
- Deleting tables
- Multiple instructions
- The semicolon
- Writing data
- Selecting fields
- Reading data
- Sorting results
- Number of columns
- Number of rows
- Changing data
- Deleting data
- Commit
- W3Schools SQL Tutorial
- SQLite SQL functions
- no need for external drivers or files
- fast, compact, stable
- doesn’t use ODBC
- multi user on NTFS on a single machine
- NOT for multiuser in a network
- no need to install aditional drivers
- http://www.sqlite.org
- PureBasic and SQLite
- suitable for large databases, stable
- needs installation on client as well as server side
- needs ODBC due to license issues
- suitable for large multi-user applications on LAN’s and WAN’s
- http://www.mysql.com
- PureBasic and MySQL
- suitable for large databases, stable
- needs installation on server side, optional installation on client side
- can use either embedded driver or ODBC
- suitable for large multi-user applications on LAN’s and WAN’s
- http://www.postgresql.com
- PureBasic and PostgreSQL
ODBC is an interface to access different sorts of databases, such as MS Access, dBase, DB2, AQL, etcetera. ODBC needs drivers, and Microsoft has included a number of them, but sometimes you might have to add one, for example for MySQL.
32 bits versus 64 bits
Windows at its best! If you run software on a 64 bits platform you may encounter the following error:
SQLite Database Browser
There’s a handy tool for checking our results when messing with SQLite databases, the SQLite Database Browser. I’m not sure if it’s actively maintained (probably not :-)) but it seems to work well for basic things. Download the .zip file and use the program inside to investigate your SQLite database files.
You can test your SQL instructions in this program using the third tab called ‘Execute SQL’. Enter the instructions and then hit the ‘Execute Query’ button.
- this program seems to have some trouble using shared access, you may have to exit and restart it to give PureBasic access again to an open database
- it also appears to have some troubles with multiple instructions at once (grouped together using the semicolon)
- it may be using a different engine than PureBasic (I had troubles with BEGIN / COMMIT)
- you may opt for the MySQL Query Browser in combination with MySQL, or the build-in PostgreSQL query browser
AKA talk to the engine.
PureBasic supports different flavours of databases. To include all routines needed for accessing SQLite databases we add to our code:
Talking to SQL
SQL is more or less a programming language, a little like PureBasic. We ‘throw’ instructions at the SQL engine, which in turn takes certain actions. PureBasic has a very limited vocubalary related to databases, as it doesn’t need much. It’s the SQL engine that does the real work, be it SQLite or MySQL or whatever other beast hides behind an ODBC interface.
These are the core commands we need to talk to the SQL engine:
DatabaseError()
DatabaseError() returns the last error the database ran into. With this we can get a textual response from the database engine which further specifies the problem we may have ran into.
DatabaseUpdate()
DatabaseUpdate() sends a command to the database engine, but doesn’t expect a reply. We use this to create tables, add colums, set fields etc. If this command returns a zero, then something went wrong (perhaps the SQL statement was wrong, or the database had problems). In those cases you can get more information about the error using DatabaseError().
DatabaseQuery()
DatabaseQuery() asks the database engine a question, and (may) trigger a number of replies. Each reply is retrieved with NextDatabaseRow(). DatabaseQuery() itself will return zero if it encountered an error.
When you are done with your query you have to call FinishDatabaseQuery() to avoid memory leaks.
SQL: Creating tables
In a database we can have multiple tables. Each table consists of rows and colums, like this:
TABLE: cars COLUMN: firstname COLUMN: lastname COLUMN: brand COLUMN: colour jan peter balkenende volvo black michael schumacher ferrari red johnny fireman mack red mick jagger cadillac black
Each table has a name, so we can store multiple names in a database. In this case ‘cars’. Let’s create the table first. The SQLite command for creating a table with one column ‘firstname’ would be:
In PureBasic we’d have to send that instruction to the SQL engine using:
We could add columns to an existing table using this:
Multiple instructions
You could send the above to SQLite using multiple DatabaseUpdate() commands:
Of course, we can also delete tables using:
Use them. Though some dialects do not seem to care, it’s better to use them. The results of a wrongly composed SQL statement can be disastrous.
13.3 Reading and writing data
Can’t read from an empty table, so let’s start with writing. (I should have called this ‘writing and reading data’, I guess. )
We’ve build our table using CREATE TABLE and now we need to put in some data. In SQLite we use INSERT and that would look something like this:
Reading and sorting
In SQL we can read from a table using the SELECT keyword. If we would like to get all rows where the colour of the car is black, we’d use:
To return the results in a specific order, we’d add ORDER BY:
- how many rows are returned upon our query?
- how many columns does our selection feature?
Want to know in advance how many rows a query will return? Use the SQL COUNT function:
Changing and deleting
You can change any field using the following SQL command UPDATE. The following line changes each and every colour of the cars belonging to the person with the last name ‘balkenende’:
SQLite types.
- in SQLite, any type of data may be stored in any column
- SQLite tries to autoformat data according to the defined column type
-
UseSQLiteDatabase()
If CreateFile(1,»d:\database.sqlite»)
CloseFile(1)
EndIf
OpenDatabase(1,»d:\database.sqlite»,»»,»»,#PB_Database_SQLite)
DatabaseUpdate(1, «CREATE TABLE types ( text TEXT , integer INTEGER , real REAL , blob BLOB)» )
;
; add some text strings
;
DatabaseUpdate(1, «INSERT INTO types VALUES ( ‘text1’ , ‘text2’ , ‘text3’ , ‘text4’ ) ;» )
;
; now add some integer numbers
;
DatabaseUpdate(1, «INSERT INTO types VALUES ( 5 , 6 , 7 , 8 ) ;» )
CloseDatabase(1)
Whilst SQLite converts the datatypes for us on the fly, we still need to store them into PureBasic variables. For your convenience we got a few different models on offer.
For reading we can use GetDatabaseLong() and its brethern, as listed below:
variable type read write .b byte a.b = GetDatabaseLong() x.s = Str(a.b) .w word b.w = GetDatabaseLong() x.s = Str(b.w) .l long c.l = GetDatabaseLong() x.s = Str(c.l) .i integer d.i = GetDatabaseQuad() x.s = Str(d.i) .q quad e.q = GetDatabaseQuad() x.s = Str(e.q) .f float f.f = GetDatabaseFloat() x.s = StrF(f.f) .d double g.d = GetDatabaseDouble() x.s = StrD(g.d) .s string s.s = GetDatabaseString() x.s = s.s
To be committed, or not to be committed, that’s the question
And indeed it is.
In SQLite, data is immediately stored in the database (‘autocommit’) as soon as a query or update is send. That is, if we don’t tell SQLite to wait. It is possible to group a number of instructions together, and have them executed at once. If, for some reason, we want to cancel our transaction, we can do a rollback before we commit ourselves.
Again, the Survival Guide is not about teaching you SQL or even SQLite 🙂 so have a good look at the SQLite documentation for the different transaction types.
The extracted SQLite instructions (doesn’t work when entered on the ‘Execute SQL’ panel inside the SQLite Database Browser, perhaps because that one uses an older version of SQLite?).
I never would. Never. At least not in your face 🙂
- store the images elsewhere and link to them
- store the images as Base64
- store the images as Yenc
- do the real thing with Blob’s
It may sound funny, but sometimes the right way to store images inside a database is not to store them inside the database. euh. argh! 🙂
Seriuosly, imagine you have a relative small database and a large collection of AutoCad drawings, stored on some drive. Those drawings are updated using AutoCad, so AutoCad needs access to them. It would be a pain in the . if you would have to export the drawings each and every time from the database, store them locally, edit them, then import them back into the database.
In those cases it may be a very valid option to simply create a text field with a path to the document.
One note though: it may be wise to think in advance how to deal with (absolute) paths, and what must be done if files are moved from one drive to another. Manual renaming may not be such a ‘comfortable’ option.
So, how can we store binary informaton then? We could store them in a string (though we have to make sure the resulting string complies to the rules, ie. no CHR(0) NULL characters are allowed). One way to do this is use Base64 encoding, this is an old encoding scheme used to transport binary data over media that do not support binary data. The example from the help file shows how to use this with a string as an example. Of course nothing would stop you to encode an image, just point towards the place in memory where the image is located, and pass on the length. See the help file.
(By the way, you need to switch off ‘Enable ASM Inline Support’ in ‘Compiler Options’ for the sample below, otherwise the PureBasic compiler thinks test, dec and enc are assembly instructions :-))
Yenc is the modern day version of Base64. It’s immense popular due to its use in newsgroups where it is used to spread binaries. PureBasic does not have a native Yenc onboard but you can code one.
Still not done. Sorry.
4.40b1 brought us the Blob. (Actually, I think McDonalds was first, but I might be wrong :-)) There’s little explanation in the not-yet-ready docs of the beta, but thanks to my exceptional sleuthing talents (and the answers in the forum :-)) here’s what’s going on:
- A blob is a set of raw, binary data. You can store anything in it, for example images or sounds.
- It may not always be the best option to store images inside your database. Design carefully.
SetDatabaseBlob()
With the statement SetDatabaseBlob() we prepare some data to be ‘blobbed’. If you look at the DatabaseUpdate() statement in the sample code above, you will find two questionmarks. We’re using these questionmarks as placeholders, and these questionmarks / placeholders will be replaced with with our blob data upon execution.
-
SetDatabaseBlob(0,0,@a,4)
SetDatabaseBlob(0,1,@c,4)
DatabaseUpdate(0, «INSERT INTO rubbish ( blob1_data , nouse , blob2_data ) VALUES ( ? , ‘1’ , ? ) ;»)
- Column 0 aka blob1_data) — first placeholder / questionmark number 0 (remember: start counting at zero) — it is replaced by the data we prepared with SetDatabaseBlob() in this case the memory contents at @a
- Column 1 aka nouse — we store ‘1’.
- Column 2 aka blob2_data — second placeholder / questionmark number 1 — it is replaced by the data we prepared, in this case the memory contents at @b.
GetDatabaseBlob()
Zoom in on the sample code above, and look for these three lines:
The second parameter of GetDatabaseBlob() speficies the table column number. This is NOT the same as the ‘index’ used by SetDatabaseBlob().
DatabaseColumnSize()
The command DatabaseColumnSize() returns the size of the specified column of the selected row. This means you can insert a blob and later retrieve first the blob size, allocate memory, then retrieve the blob data using the following approach:
You can have multiple databases, and multiple tables. It is possible to retrieve information on a table, but this only works after you have executed a SELECT statement.
The code below uses DatabaseColums() to retrieve the number of columns, then shows the name of each column using the DatabaseColumnName() command.
Note to self: check and expand.
I f an SQL database is an essential part of your solution, you should consider PostgreSQL. MySQL has some license issues, and needs an ODBC connector.
MySQL is one of the most well-known SQL server packages. Note that there is dispute about the usability / legality in a commercial environment, due to some license restrictions. It appears to me that you can use it, but that you will have to use ODBC to avoid license issues. You may consider PostgreSQL as an alternative.
Again, this is not a tutorial on SQL, MySQL, or ODBC. I’m only interested in setting things up so I can use PureBasic to mess around with them 🙂 Still it is worth it to have another look at the issue in case we’d become too succesful 🙂
Some notes on the license issue. I’m not a lawyer (otherwise I would be working for a patent troll, be indencently rich, and not be writing this :-)) so take the following at face value. In other words, my humble opinion, your mileage may vary, at your own risk, disclaimers etc. etc. etc.
Unless you BUY a license of MySQL you need to adhere to the GPL. As far as I can tell nothing is going to stop you from using MySQL in a non-commercial or commercial project, as long as you adhere to the license. The key is the term ‘derivative work’.
1. Embedding GPL’ed SOURCE in your code would clearly force you to use the GPL license for your whole product.
2. STATIC LINKING of a GPL’ed library makes the GPL’ed code and resulting program part of your program and thus forces you to use the GPL license.
3. DYNAMIC LINKING is a bit more tricky. Strictly spoken the functionality of the DLL becomes part of your program, but the code itself does not. The jury is still out on this one. If your program would use functionality exposed by an under GPL developed and distributed DLL, which DLL was developed and distributed for such a purpose, and which DLL is not distributed as part of your program, then you’re probably not obliged to go GPL. However, it’s inside the grey zone.
4. If the whole GPL’ed program is an integral element of your solution, and you would install it (perhaps automatically) as part of your (commercial) solution, you’d be entering the grey zone as well. Most definitely if you would hide such an installation from the user (as part of a commercial package).
The above doesn’t stop you from using MySQL. Using functionality provided / exposed by MySQL ODBC connector software, or communicating with the MySQL server is not considered derivative work so should be fine. You (probably) cannot automagically install MySQL and / or the MySQL ODBC connector, and you (definitely) cannot embed a MySQL library in your program. But nothing is going to stop you from installing or using a MySQL platform as part of a commercial and / or non-GPL’ed solution, it just cannot be part of your program.
The above was written in 2010. Who knows what has changed since then, so go and check that license before doing something stupid 🙂
13.22 Installation server side.
You might want to run this on a dedicated machine, server, or virtual machine. I used VirtualBox to setup such a ‘dedicated’ MySQL server on a virtual machine. Read more about using VirtualBox here. MySQL needs one side to be a server, and the other to be a client, but nothing is stopping you to install server and client software on the same machine. (Frankly, if you’re just going to use MySQL as a simple local database, there’s very little reason to use a dedicated machine, but then again why are you not using SQLite then?)
There are complete packages around including tools, configuration etc. such as Xampp. They may make your life easier, especially if you’re interested in building applications for the web. I may revisit Xampp once I find the courage to use PureBasic for web applications. For now, it’s though enough as it is 🙂
Machine and Windows
Create a VM if you’re going to use VirtualBox or something similar. You may consider assigning a fixed IP to your server. I changed the name of my dedicated MySQL server to ‘sqlserver’.
MySQL 5.1.38 and MySQL Essentials 5.1
1. Download the MySQL server essentials package and install it. I used 5.1 and ticked the option ‘custom’ as I like to think of myself as an expert (which, obviously, I am not :-)). Note: when reinstalling MySQL it couldn’t start the service, no matter what I tried. In the end, I cloned a new VM and reinstalled. (I should have used a snapshot in VirtualBox but I forgot to create one :-)) I think I messed up a password which wasn’t removed during de-installation, but that’s the good thing about imaging and / or virtual machines. restoring is a lot easier.
2. The default port is 3306. Tick the box ‘add firewall exception’ if you’re using Windows firewall. Note: this may not suffice, and you might have to allow traffic manually! When in doubt, check functionality by shutting down the firewall temporary. Oh, and if you are using the host name on the client to find the server, enable ‘file and printer sharing’ on that server otherwise the client won’t find the host!
3. Tick ‘best support for multilingualism’. Install as a Windows service and have it launched automatically. Also tick the option ‘include bin directory in path’. Next etc.
4. Modify security settings and enter a new root password. For simplicity I used the password ‘root’ here. not very safe, but this is a test environment, not a production server. Next etc.
5. Hit the ‘execute’ button and hope it doesn’t crash during installation. (It did here twice. ) Next etc.
Tada. You’ve now got your own MySQL server up and running as a service on your virtual machine. Congratulations.
Don’t forget to open the appropriate port(s) in your firewall.
MySQL GUI Tools 5.0
Note: these seem to have been replaced by the MySQL Workbench.
These tools make your life a little easier, unless you’re a die-hard that likes the command prompt.
1. Download and install the GUI tools package and install it. I used 5.0 and did install all except the MySQL migration toolkit. Next, install, finish etc, you know the drill.
2. Under Windows Start / Programs you’ll find a new folder MySql. Start the MySQL Tray Monitor. Click on it with the RMB.
3. Switch ON the option Monitor Options / Launch Monitor After Login.
4. There’s another tool you’ll find there called MySQL Administrator. You may want to drag it onto the desktop for quick access.
You can now test your setup.
Note that you can install the MySQL GUI Tools on your clients, if you want to. Especially the MySQL Query Browser may come in handy if you want to experiment with the SQL language itself.
MySQL Workbench 5.2 CE
This seems to have replaced the MySQL GUI Tools. I’ve tried this one on a client to execute queries and it worked fine.
- server host: localhost
- port: 3306
- username: root
- password: root
Adding a user
Start the MySQL Administrator on your new SQL server and log in as root. Select Use Administration / Add New User. I added a new user called ‘user’ with password ‘user’. (Yes, I’m a very creative person.)
Creating a database
- server host: localhost
- port: 3306
- username: root
- password: root
- default schema: test
Obvously, you should only create it once. executing CREATE DATABASE PUREBASIC a second time will throw an error. It already existed 🙂
In all future calls we might use the MySQL Query Browser with ‘default schema’ set to purebasic, we just needed that build-in ‘test’ database this one time to start up the query browser and create our own first database. The program is supposed to let us connect to the MySQL service without a database given, but I didn’t get through without one.
In the 2013 MySQL Workbench I received an error. Adding semicolons fixed it:
13.23 Installation client side
There is more than one way to talk to the MySQL server, but from within PureBasic the easiest one is using ODBC.
MySQL ODBC Connecter
1. Download the MySQL ODBC connector for Windows and run it.
2. Look for Start / Programs / Administrative Tools / Data Sources (ODBC) and start it. This tool may be located somewhere else on your machine, for example on my Windows 7 box it could be accessed via Control Panel / Data Sources (ODBC).
- data source name: mysql
- server: sqlserver (this is the name I gave my dedicated MySQL server)
- posrt:3306
- user: root
- password: root
- database: purebasic
64 bit users be aware! There are TWO different versions of ODBC on your machine!
Typically if you run into the following error, you’re using the wrong one (mostly by trying to access the 64 bits ODBC from a 32 bits application):
Anyway, if things worked out well, you should be seeing something like this:
4. Hit the ‘Test’ button. If the ODBC connector cannot connect to our MySQL Server then most likely a firewall is causing the problem, either on the client or on the server. Try it with the firewalls turned off. If that works, you might test with the IP address of the server instead of its name, ortry
5. Run the program below. It should create a little table and produce the same results as our SQLite version.
Of course, you could also install the MySQL Workbench on your client machine, to verify the results of your code, and experiment with SQL queries outside of PureBasic.
13.24 SQLite to MySQL
From a PureBasic and SQL point of view there is little difference between MySQL and SQLite. It’s important to keep in mind that MySQL is more strict on data types.
- install the neccessary software on server and client
- create a database and users on the server
- speficy the right database on the client (ODBC configuration)
- remove the creation of a local file (not needed for MySQL)
- replace UseSQLiteDatabase() with UseODBCDatabase()
- change the parameters for the OpenDatabase() command
- add semicolons
- use BEGIN and COMMIT
In SQLite with a single user application you might skip BEGIN / COMMIT but in multi user applications in a network I would strongly advise to use them.
PostgreSQL is ‘the other’ open source database, but it doesn’t suffer from GPL issues. This means that PostgreSQL drivers / libraries can be linked with / embedded in other programs. Which is exactly what PureBasic did 🙂
You will always need to install PostgreSQL on the server side. You may chose to use ODBC on the client side, or use the onboard drivers of PureBasic.
I found the installation and configuration of MySQL marginally easer, and the MySQL GUI tools are nice, especially the MySQL Query Browser. However PostgreSQL contains a similar tool, and if you look around on the Internet you’ll find some alternatives, I’m sure.
13.26 Installation server side
PostgreSQL needs one side to be a server, and the other to be a client, but nothing is stopping you to install server and client software on the same machine. (Frankly, if you’re just going to use PostgreSQL as a simple local database, there’s very little reason to use a dedicated machine, but then again why are you not using SQLite then?)
Machine and Windows
Create a VM if you’re going to use VirtualBox or something similar. You may consider assigning a fixed IP to your server. I created a new VM and changed its name to ‘sqlserver’. In fact, I installed MySQL and ProgreSQL on the same VM without any problems.
PostgreSQL 8.4.1
1. Download PostgreSQL 8.4.1. Use the regular package and install it.
2. The default port is 5432. Choose eventual passwords wisely. (I did not, so ‘postgres’ it is, everywhere :-)) Install.
3. Look for a file called ‘pg_hba.conf’. It’s in the PostgreSQL folders somewhere. If your local network runs in the 192.168.0.x range, then you will have to add the following line:
5. You may want to put the link ‘Postgress pgAdmin III’ on your desktop for easy access.
6. Start up pgAdmin. Connect to (doubleclick) the PostgreSQL server (localhost port 5432 user postgres password postgres).
7. RMB on ‘databases’ and add a new database called ‘purebasic’.
Don’t forget to open the appropriate port(s) in your firewall.
The PostgreSQL query browser
PostgreSQL also includes a query browser. To use it do the following:
1. Start up pgAdmin.
2. Select ‘purebasic’ under ‘Databases’.
3. EIther select Tools / Query tool, or hit [Control] + [E]. Note that some commands that work under MySQL don’t work on PostgreSQL.
13.27 Installation client side
Seriously, you could do an ODBC client side install, but PureBasic already contains the PostgreSQL library, so there’s no real need.
Use the following code to check if your PostgreSQL setup is working:
Of course, I couldn’t help myself and had to try 🙂
1. Get the ODBC connector software, the one I used I found on the PostgreSQL website, under file browser / odbc / versions / msi / psqlodbc_08_04_0100.zip.
2. Unzip and install it.
2. Look for Start / Programs / Administrative Tools / Data Sources (ODBC) and start it. This tool may be located somewhere else on your machine.
- data source: postgresql
- server: sqlserver
- port: 5432
- user: postgres
- password: postgres
- database: purebasic
6. Try the following program:
13.28 MS SQL Express 2008
Well, there should be no reason why not to try MicroSoft’s latest 🙂 unfortunately I’m running XP in the VM, so I can’t test it with 2012. Let’s try it with an older version then: SQL Express 2008 on Windows XP.
Server side
Unfortunately, it’s not as easy to setup. I’ve got no clue about all those MS SQL options, but the ones below got me started. Information on this page helped me to get started.
Note that I wanted explictly to communicate with the database via TCP, port, and SQL user / password. If you’re using NT authentication this just might be a lot easier.
- create a VM or build a real server
- make sure the VM has at least 256 MB (I managed to run MySQL, PostGreSQL and MS SQL simultaneously in 384 MB, let’s not talk performance :-))
- download and install .NET 3.5 SP1, you might have to reboot
- download and install Windows Power Shell 1.0
- download and install Windows Installer 4.50
- do a Windows update to see if you’ve missed any patches (I got lots of ‘m, took ages to install)
- download and install MS SQL Express 2008
- in the SQL Server Installation Center, pick ‘stand-alone installation’
- next accept next etc. etc.
- Feauture Selection / Database Engine Services
- Server Configuration / Account: NT AUTHORITY\SYSTEM
- Database Engine Configuration: Mixed Mode, add a password (for example ‘apekop’), add some users
- next / next / install etc. and finish installation
- Start / Programs / Microsoft SQL Server 2008 / Configuration Tools / SQL Server Configuration Manager
- RMB on SQL Server Network Configuration / Protocols, enable
- RMB on SQL Server Network Configuration / Protocols, properties
- tab Protocol
- Enabled: yes
- Listen All: yes
- IP1 / Active: yes
- IP1 / Enabled: yes
- IP1 / IP Address: 192.168.0.71 (my server’s address)
- IP1 / TCP Dynamic Ports: empty
- IP1 / TCP Port: 1433
- IP2 / Active: no
- IP2 / Enabled: no
- IPAll / TCP Dynamic Ports: empty
- IPAll / TCP Port: 1433
- connect to a database
- Server name: 192.168.0.71
- Authentication: SQL Server Authentication
- Login: sa
- Password: apekop
- New Query
- CREATE DATABASE purebasic
Client side
- Add SQL Server
- Name: sqlexpress (this is the name I used in my PureBasic code)
- Server: 192.168.0.71
- Next
- select SQL Server authentication
- Client Configuration
- Server alias: 192.168.0.71
- TCP/IP
- Server name: 192.168.0.71
- unselect Dynamically determine port (you may have to click a few times before you can enter a port number)
- Port number: 1433
- Ok
Use the following code to check if your SQL Express 2008 setup is working:
Как сделать таблицу в purebasic
Определить принадлежит ли точка с координатами, введенными пользователем, заштрихованным областям
Определить принадлежит ли точка с координатами, введенными пользователем, изображенным на рисунке.
Произвести определенные действия над введенными пользователем числами в зависимости от этих чисел
Ввести числа: натуральные m и n и вещественное x. Если частное от деления m на n четное, то.PureBasic Forums — English
The conventional filing system is a very adequate means of storing data for almost any requirement. However, speed and performance might prove an issue in cases of large and unstructured datasets.
Databases, on the other hand, are designed to handle multiple tables, each acting like independent files, indexed and safely stored according to data size and type. And they do this with great speed and efficiency.
Among the databases that are supported in PureBasic, SQLite is the easiest and most lightweight option that could justifiably substitute the use of conventional files. Moreover, it’s quite easy and straightforward to implement and utilise.
This short step-by-step tutorial aims to demonstrate the syntax and usage of PureBasic’s built-in SQLite functions. Please do take note that the sample snippets should be run sequentially, as most depend on the preceding ones in order to obtain the correct results and output.
Creating an empty file for the database
A new file named sqliteFile.sqlite will be created to be used as the database file that will be created in the next step. Take note that if the file already exists it will be overwritten with a new empty file. This step is required only once, so be careful not to accidentally overwrite a healthy database.
Creating a new SQLite database
We’ve successfully created a fully structured SQLite database file. Let’s write some data to it.
Writing data to SQLite database
Now, we’ve successfully written some data to the SQLite database. So, let’s try to retrieve them.
Reading data from SQLite database (reading routine)
Et Voila! We’ve successfully created, written to, and read from an SQLite database. Notice that in this snippet, there’s an additional function, FinishDatabaseQuery(), called before the database is closed. This is only required after calls to the DatabaseQuery() function to clean-up and free resources used while reading and retrieving data from the database. It is not required after calls to the DatabaseUpdate() function.
Also, the first record was inserted into the database through literal queries, meaning that the values were manually inserted into the query strings themselves (eg: name=’Billy Joel’). The next snippet will insert data values through a method called data binding.
Writing data to SQLite database with data binding
Notice that the variables are bound to the query based on the order of the field names in the query and the index values of the SetDatabase_xxx() functions. Another two records have been inserted into the SQLite database, so let’s take a look. The next snippet is a repetition of the earlier one to read the database.
Reading data from SQLite database (reading routine)
So far, so good. Now, let’s try multiple data insertions in a loop.
Writing data to SQLite database in a loop
We’ve quite covered the basics of SQLite database reading and writing. Time to delve deeper.
Updating existing data in SQLite database
Good progress. But we’re not quite done yet. Let’s try and delete a record.
Deleting existing data in SQLite database
So far, we’ve only performed wildcard reads from the database without any conditional filters. This means that all records in the database are retrieved. In the next snippet, we’ll apply some filters to the queries to read records based on criteria.
Reading data from SQLite database with conditional queries (conditional reading routine)
When we first created the database, we created a table with five fields; id, name, age, address, and telephone. What if we needed to expand this table to include more fields? Let’s do that now.
Altering the SQLite database table
Now, it’s time to address a fairly important aspect of databases; BLOBs. A BLOB is an acronym for Binary Large Object, which is an SQL data type for storing large data with no particular size or structure. It can be used to store entire files, images, audio & video clips, and anything else. These next two snippets demonstrate the methods for writing and reading BLOBs in PureBasic.
Writing BLOB data into SQLite database
In the above snippet, a new column named PICTURE was first added into the SQLite database table. Then a sample image file from PureBasic’s samples folder was opened and read into memory. Finally, the contents of the image file was bound with the query to insert it into the database.
For this example, please ensure that the paths to PureBasic’s sample folder and image are correct. Alternatively, any image file can be substituted in its place, along with the relevant image libraries (UseJPEG_xxx, UsePNG_xxx, etc).
This next and final snippet reads Bob Dylan’s contact record from the database, including the newly inserted image, and displays them in a demo window:
And that’s about it for this tutorial!
While we’ve covered almost all the fundamental aspects of using SQLite databases in PureBasic, there is still a vast scope of functionalities that can be applied, from structured and modular executions, to complex and compound SQLite queries and transactions. Nevertheless, this should provide a fairly decent foundation to get started with database programming.
A practical example of these functions in action can be found in this little utility:
Как сделать таблицу в purebasic
13.1 As I go. again
Welcome to my totally unstructured approach to databases, and may I end up where I want to be. (If I only knew where that would be :-)) I’m going to talk about SQLite and MySQL.
- Creating tables
- Adding columns
- Deleting tables
- Multiple instructions
- The semicolon
- Writing data
- Selecting fields
- Reading data
- Sorting results
- Number of columns
- Number of rows
- Changing data
- Deleting data
- Commit
- W3Schools SQL Tutorial
- SQLite SQL functions
- no need for external drivers or files
- fast, compact, stable
- doesn’t use ODBC
- multi user on NTFS on a single machine
- NOT for multiuser in a network
- no need to install aditional drivers
- http://www.sqlite.org
- PureBasic and SQLite
- suitable for large databases, stable
- needs installation on client as well as server side
- needs ODBC due to license issues
- suitable for large multi-user applications on LAN’s and WAN’s
- http://www.mysql.com
- PureBasic and MySQL
- suitable for large databases, stable
- needs installation on server side, optional installation on client side
- can use either embedded driver or ODBC
- suitable for large multi-user applications on LAN’s and WAN’s
- http://www.postgresql.com
- PureBasic and PostgreSQL
ODBC is an interface to access different sorts of databases, such as MS Access, dBase, DB2, AQL, etcetera. ODBC needs drivers, and Microsoft has included a number of them, but sometimes you might have to add one, for example for MySQL.
32 bits versus 64 bits
Windows at its best! If you run software on a 64 bits platform you may encounter the following error:
SQLite Database Browser
There’s a handy tool for checking our results when messing with SQLite databases, the SQLite Database Browser. I’m not sure if it’s actively maintained (probably not :-)) but it seems to work well for basic things. Download the .zip file and use the program inside to investigate your SQLite database files.
You can test your SQL instructions in this program using the third tab called ‘Execute SQL’. Enter the instructions and then hit the ‘Execute Query’ button.
- this program seems to have some trouble using shared access, you may have to exit and restart it to give PureBasic access again to an open database
- it also appears to have some troubles with multiple instructions at once (grouped together using the semicolon)
- it may be using a different engine than PureBasic (I had troubles with BEGIN / COMMIT)
- you may opt for the MySQL Query Browser in combination with MySQL, or the build-in PostgreSQL query browser
AKA talk to the engine.
PureBasic supports different flavours of databases. To include all routines needed for accessing SQLite databases we add to our code:
Talking to SQL
SQL is more or less a programming language, a little like PureBasic. We ‘throw’ instructions at the SQL engine, which in turn takes certain actions. PureBasic has a very limited vocubalary related to databases, as it doesn’t need much. It’s the SQL engine that does the real work, be it SQLite or MySQL or whatever other beast hides behind an ODBC interface.
These are the core commands we need to talk to the SQL engine:
DatabaseError()
DatabaseError() returns the last error the database ran into. With this we can get a textual response from the database engine which further specifies the problem we may have ran into.
DatabaseUpdate()
DatabaseUpdate() sends a command to the database engine, but doesn’t expect a reply. We use this to create tables, add colums, set fields etc. If this command returns a zero, then something went wrong (perhaps the SQL statement was wrong, or the database had problems). In those cases you can get more information about the error using DatabaseError().
DatabaseQuery()
DatabaseQuery() asks the database engine a question, and (may) trigger a number of replies. Each reply is retrieved with NextDatabaseRow(). DatabaseQuery() itself will return zero if it encountered an error.
When you are done with your query you have to call FinishDatabaseQuery() to avoid memory leaks.
SQL: Creating tables
In a database we can have multiple tables. Each table consists of rows and colums, like this:
TABLE: cars COLUMN: firstname COLUMN: lastname COLUMN: brand COLUMN: colour jan peter balkenende volvo black michael schumacher ferrari red johnny fireman mack red mick jagger cadillac black Each table has a name, so we can store multiple names in a database. In this case ‘cars’. Let’s create the table first. The SQLite command for creating a table with one column ‘firstname’ would be:
In PureBasic we’d have to send that instruction to the SQL engine using:
We could add columns to an existing table using this:
Multiple instructions
You could send the above to SQLite using multiple DatabaseUpdate() commands:
Of course, we can also delete tables using:
Use them. Though some dialects do not seem to care, it’s better to use them. The results of a wrongly composed SQL statement can be disastrous.
13.3 Reading and writing data
Can’t read from an empty table, so let’s start with writing. (I should have called this ‘writing and reading data’, I guess. )
We’ve build our table using CREATE TABLE and now we need to put in some data. In SQLite we use INSERT and that would look something like this:
Reading and sorting
In SQL we can read from a table using the SELECT keyword. If we would like to get all rows where the colour of the car is black, we’d use:
To return the results in a specific order, we’d add ORDER BY:
- how many rows are returned upon our query?
- how many columns does our selection feature?
Want to know in advance how many rows a query will return? Use the SQL COUNT function:
Changing and deleting
You can change any field using the following SQL command UPDATE. The following line changes each and every colour of the cars belonging to the person with the last name ‘balkenende’:
SQLite types.
- in SQLite, any type of data may be stored in any column
- SQLite tries to autoformat data according to the defined column type
-
UseSQLiteDatabase()
If CreateFile(1,»d:\database.sqlite»)
CloseFile(1)
EndIf
OpenDatabase(1,»d:\database.sqlite»,»»,»»,#PB_Database_SQLite)
DatabaseUpdate(1, «CREATE TABLE types ( text TEXT , integer INTEGER , real REAL , blob BLOB)» )
;
; add some text strings
;
DatabaseUpdate(1, «INSERT INTO types VALUES ( ‘text1’ , ‘text2’ , ‘text3’ , ‘text4’ ) ;» )
;
; now add some integer numbers
;
DatabaseUpdate(1, «INSERT INTO types VALUES ( 5 , 6 , 7 , 8 ) ;» )
CloseDatabase(1) - store the images elsewhere and link to them
- store the images as Base64
- store the images as Yenc
- do the real thing with Blob’s
- A blob is a set of raw, binary data. You can store anything in it, for example images or sounds.
- It may not always be the best option to store images inside your database. Design carefully.
Whilst SQLite converts the datatypes for us on the fly, we still need to store them into PureBasic variables. For your convenience we got a few different models on offer.
For reading we can use GetDatabaseLong() and its brethern, as listed below:
variable type read write .b byte a.b = GetDatabaseLong() x.s = Str(a.b) .w word b.w = GetDatabaseLong() x.s = Str(b.w) .l long c.l = GetDatabaseLong() x.s = Str(c.l) .i integer d.i = GetDatabaseQuad() x.s = Str(d.i) .q quad e.q = GetDatabaseQuad() x.s = Str(e.q) .f float f.f = GetDatabaseFloat() x.s = StrF(f.f) .d double g.d = GetDatabaseDouble() x.s = StrD(g.d) .s string s.s = GetDatabaseString() x.s = s.s To be committed, or not to be committed, that’s the question
And indeed it is.
In SQLite, data is immediately stored in the database (‘autocommit’) as soon as a query or update is send. That is, if we don’t tell SQLite to wait. It is possible to group a number of instructions together, and have them executed at once. If, for some reason, we want to cancel our transaction, we can do a rollback before we commit ourselves.
Again, the Survival Guide is not about teaching you SQL or even SQLite 🙂 so have a good look at the SQLite documentation for the different transaction types.
The extracted SQLite instructions (doesn’t work when entered on the ‘Execute SQL’ panel inside the SQLite Database Browser, perhaps because that one uses an older version of SQLite?).
I never would. Never. At least not in your face 🙂
It may sound funny, but sometimes the right way to store images inside a database is not to store them inside the database. euh. argh! 🙂
Seriuosly, imagine you have a relative small database and a large collection of AutoCad drawings, stored on some drive. Those drawings are updated using AutoCad, so AutoCad needs access to them. It would be a pain in the . if you would have to export the drawings each and every time from the database, store them locally, edit them, then import them back into the database.
In those cases it may be a very valid option to simply create a text field with a path to the document.
One note though: it may be wise to think in advance how to deal with (absolute) paths, and what must be done if files are moved from one drive to another. Manual renaming may not be such a ‘comfortable’ option.
So, how can we store binary informaton then? We could store them in a string (though we have to make sure the resulting string complies to the rules, ie. no CHR(0) NULL characters are allowed). One way to do this is use Base64 encoding, this is an old encoding scheme used to transport binary data over media that do not support binary data. The example from the help file shows how to use this with a string as an example. Of course nothing would stop you to encode an image, just point towards the place in memory where the image is located, and pass on the length. See the help file.
(By the way, you need to switch off ‘Enable ASM Inline Support’ in ‘Compiler Options’ for the sample below, otherwise the PureBasic compiler thinks test, dec and enc are assembly instructions :-))
Yenc is the modern day version of Base64. It’s immense popular due to its use in newsgroups where it is used to spread binaries. PureBasic does not have a native Yenc onboard but you can code one.
Still not done. Sorry.
4.40b1 brought us the Blob. (Actually, I think McDonalds was first, but I might be wrong :-)) There’s little explanation in the not-yet-ready docs of the beta, but thanks to my exceptional sleuthing talents (and the answers in the forum :-)) here’s what’s going on:
SetDatabaseBlob()
With the statement SetDatabaseBlob() we prepare some data to be ‘blobbed’. If you look at the DatabaseUpdate() statement in the sample code above, you will find two questionmarks. We’re using these questionmarks as placeholders, and these questionmarks / placeholders will be replaced with with our blob data upon execution.
-
SetDatabaseBlob(0,0,@a,4)
SetDatabaseBlob(0,1,@c,4)
DatabaseUpdate(0, «INSERT INTO rubbish ( blob1_data , nouse , blob2_data ) VALUES ( ? , ‘1’ , ? ) ;») - Column 0 aka blob1_data) — first placeholder / questionmark number 0 (remember: start counting at zero) — it is replaced by the data we prepared with SetDatabaseBlob() in this case the memory contents at @a
- Column 1 aka nouse — we store ‘1’.
- Column 2 aka blob2_data — second placeholder / questionmark number 1 — it is replaced by the data we prepared, in this case the memory contents at @b.
- server host: localhost
- port: 3306
- username: root
- password: root
- server host: localhost
- port: 3306
- username: root
- password: root
- default schema: test
- data source name: mysql
- server: sqlserver (this is the name I gave my dedicated MySQL server)
- posrt:3306
- user: root
- password: root
- database: purebasic
- install the neccessary software on server and client
- create a database and users on the server
- speficy the right database on the client (ODBC configuration)
- remove the creation of a local file (not needed for MySQL)
- replace UseSQLiteDatabase() with UseODBCDatabase()
- change the parameters for the OpenDatabase() command
- add semicolons
- use BEGIN and COMMIT
- data source: postgresql
- server: sqlserver
- port: 5432
- user: postgres
- password: postgres
- database: purebasic
- create a VM or build a real server
- make sure the VM has at least 256 MB (I managed to run MySQL, PostGreSQL and MS SQL simultaneously in 384 MB, let’s not talk performance :-))
- download and install .NET 3.5 SP1, you might have to reboot
- download and install Windows Power Shell 1.0
- download and install Windows Installer 4.50
- do a Windows update to see if you’ve missed any patches (I got lots of ‘m, took ages to install)
- download and install MS SQL Express 2008
- in the SQL Server Installation Center, pick ‘stand-alone installation’
- next accept next etc. etc.
- Feauture Selection / Database Engine Services
- Server Configuration / Account: NT AUTHORITY\SYSTEM
- Database Engine Configuration: Mixed Mode, add a password (for example ‘apekop’), add some users
- next / next / install etc. and finish installation
- Start / Programs / Microsoft SQL Server 2008 / Configuration Tools / SQL Server Configuration Manager
- RMB on SQL Server Network Configuration / Protocols, enable
- RMB on SQL Server Network Configuration / Protocols, properties
- tab Protocol
- Enabled: yes
- Listen All: yes
- IP1 / Active: yes
- IP1 / Enabled: yes
- IP1 / IP Address: 192.168.0.71 (my server’s address)
- IP1 / TCP Dynamic Ports: empty
- IP1 / TCP Port: 1433
- IP2 / Active: no
- IP2 / Enabled: no
- IPAll / TCP Dynamic Ports: empty
- IPAll / TCP Port: 1433
- connect to a database
- Server name: 192.168.0.71
- Authentication: SQL Server Authentication
- Login: sa
- Password: apekop
- New Query
- CREATE DATABASE purebasic
Client side
- Add SQL Server
- Name: sqlexpress (this is the name I used in my PureBasic code)
- Server: 192.168.0.71
- Next
- select SQL Server authentication
- Client Configuration
- Server alias: 192.168.0.71
- TCP/IP
- Server name: 192.168.0.71
- unselect Dynamically determine port (you may have to click a few times before you can enter a port number)
- Port number: 1433
- Ok
Use the following code to check if your SQL Express 2008 setup is working:
Как сделать таблицу в purebasic
Глава 5 Вернуться

Структуры данных
В этой главе я расскажу, как создать и использовать другие методы для хранения и управления данными, такие, как структуры, массивы и связанные списки. Данные, такие как структуры необходимы для программирования игр и приложений, поскольку они позволяют получить более легкий и быстрый доступ к нескольким значениям связанных и не связанных данных. Как всегда, даются разъяснения и несколько примеров.
Структуры
Ранее, во 2 главе, я представил вам встроенные типы данных, Byte, Character, Word, Long, Quad, Float, Double и String . Используя в структуре слова c ключами(.s,.l,.b,.w,.c,.q), вы можете определить свой собственный структурированный тип данных, а затем присвоить этот тип переменной(ым). Создание собственных структурированных переменных удобно, особенно если вам понадобятся много общих имен переменных в рамках одной структуры.
Непонятно? Тогда давайте посмотрим на примере структуры, которая содержит несколько полей:Me.PERSONALDETAILS
Me\FirstName = «Gary»
Me\LastName = «Willoughby»
Me\Home = «A House»Debug «First Name: » + Me\FirstName
Debug «Last Name: » + Me\LastName
Debug «Home: » + Me\HomeСтруктура ‘ PERSONALDETAILS ‘ создается с использованием ключевого слова Structure . Далее идут компоненты структуры которые определяются точно так же, как обычные переменные. Ключевое слово EndStructure используется для определения конца структуры. После того как структура объявлена, она готова к использованию. Мы придали этой структуре тип так же, как мы
назначаем любой тип переменной, пример:Здесь имя переменной ‘ Me ‘ и его тип ‘ PERSONALDETAILS ‘. Чтобы присвоить значения отдельным
переменным (иногда называемые полями) в рамках новой ‘ Me ‘ структурированной переменной, мы используем символ ‘\’. Если вы посмотрите на пример выше, то заметите, что ‘\’, символ также используется, чтобы восстановить данные из индивидуальных полей также, как здесь:Father.PERSONALDETAILS
Father\FirstName = «Peter»
Debug Father\FirstNameЗдесь, в этом маленьком примере, мы создали новую структурированную переменную » Father «
с структурированным типом » PERSONALDETAILS «. Мы придаем значение ‘ Peter ‘ для Father\FirstName .
Затем мы вывели это значение в окне отладки. Конечно по этим примерам вы возможно не увидели пользы от структур, но они невероятно полезны.Размер памяти структурированной переменной зависит от полевой переменной, используемой в первоначальном определении структуры. В структуре » PERSONALDETAILS » определены три переменные с типом String , каждая из которых имеет размер 4 байта (см. Рис.3 ранее в главе 2 для размеров, типов String ).
Таким образом, вновь заявленная переменная ‘ Me ‘ занимает 12 байт (3 х 4 байта) в памяти. Мы можем проверить это, с помощью функции ‘ SizeOf() ‘.Structure PERSONALDETAILS
FirstName.s
LastName.s
Home.s
EndStructure
Debug SizeOf(PERSONALDETAILS)Функция ‘ sizeof() ‘ возвращает значение ’12’, которое показывает, сколько байт использует структура в памяти.
Эта команда возвращает размер любой структуры или переменной, определяемой в байтах. Она не работает с массивами, связанными списками или интерфейсом. Эта команда имеет неоценимое значение для программирования в Windows, поскольку некоторые Win32 API функции требуют размера конкретной структуры или переменной в качестве параметра. Больше о Win32 API
мы узнаем позже в главе 13.Дополнение полей из другой структуры
Структуры можно дополнить полями из другой структуры с помощью параметра ‘ Extends ’
Structure PERSONALDETAILS
FirstName.s
LastName.s
Home.s
EndStructureStructure FULLDETAILS Extends PERSONALDETAILS
Address.s
Country.s
ZipCode.s
EndStructureUser.FULLDETAILS
User\FirstName = «John»
User\LastName = «Smith»
User\Home = «A House»
User\Address = «A Street»
User\Country = «UK»
User\ZipCode = «12345»Debug «Users First Name: » + User\FirstName
Debug «Users Last Name: » + User\LastName
Debug «Users Home: » + User\Home
Debug «Users Address: » + User\Address
Debug «Users Country: » + User\Country
Debug «Users Zip Code: » + User\ZipCodeВ этом примере структуру ‘ FULLDETAILS ‘ расширяет структура ‘ PERSONALDETAILS ‘
и вновь получаемая структура дополняется данными из структуры ‘ PERSONALDETAILS ‘ , причем так, что взятые данные появляются первыми в нашей новой структуре. Мы присвоили этой новосозданной структуре переменную ‘ User ‘, ну и присвоили значения во всех ее сферах. Затем эти данные проверили в окне отладки.Структуры Union (объединенные)
Структуры Union — способ сохранить память, вынуждая группы переменных совместно использовать в пределах структуры тот же самый адрес памяти. Возможно я залез немного вперед, но поверьте мне пришлось это сделать для законченности.
Вы можете просмотреть Главу 13 (Pointers), чтобы понять лучше, как это работает. Вот простой пример:Structure UNIONSTRUCTURE
StructureUnion
One.l
Two.l
Three.l
EndStructureUnion
EndStructureПосле объявления ‘ UNIONSTRUCTURE ‘ мы использовали StructureUnion и EndStructureUnion для инкапсуляции переменных, которым мы хотим использовать одну выделенную область памяти.
Когда мы запускаем эту небольшую программу,первое что появляется в окне отладки это ‘4 ‘(байта), поскольку структура имеет размер одной переменной из-за того, что все переменные в такой структуре задействуют только одно место в памяти.Далее в программе мы присвоиваем UnionVariable тип UNIONSTRUCTUR E и назначаем значение ‘123’ для UnionVariable\One, затем считываем его в окне отладки. После мы присвоиваем новое значение ‘456’ для UnionVariable\Three , и снова считываем старую переменную UnionVariable\One . Но так как используется одна и та же область памяти для всех переменных в структуре то переменной UnionVariable\One присваивается новое значение ‘456’ которое как мы помним, мы присвоили ‘ UnionVariable\Three ‘.
Структуры могут содержать так называемые статические массивы, но мне нужно объяснить массивы, прежде чем мы может применять эти знания для структур. Массивы и статические массивы объясняются в полном объеме в следующем разделе.

Массивы
Массивы создаются с помощью команды DIM:
Позвольте мне объяснить эту строку кода более понятно. Во-первых мы используем команду Dim , чтобы сообщить компилятору, что мы собираемся определить массив. Затем мы даем имя массиву. В данном случае, я назвал его LongArray . После названия, мы аналогично переменным, присваиваем тип массиву с помощью суффикса ‘. l’. Итак, массив имеет тип Long . После того, как определен тип, нам надо определить, сколько индексов будет содержать массив.Для определения индекса используются целые числа в круглых скобках. В приведенном выше примере мы использовали (2). Это означает, что массив сможет вместить три переменных. Почему три, а не две? Потому, что отсчет в массивах всегда начинается с нуля, а цифра (2) показывает последний индекс массива.После того как массив был создан, все его переменные будут иметь тип Long. Это простой массив. Чаще такой массив называют одномерным. Давайте посмотрим на наглядном примере в котором мы определим массив и присвоим значения всем его индексам:
Dim LongArray.l(2)
LongArray(0) = 10
LongArray(1) = 25
LongArray(2) = 30
Debug LongArray(0) + LongArray(1)
Debug LongArray(1) * LongArray(2)
Debug LongArray(2) — LongArray(0)После того как мы присвоили значения переменным массива, мы произвели с ними математические операции и вывели результат в окно отладки. Например, первым результатом будет сложение ’10 + 25 ‘,поскольку мы сложили индексы ‘0 ‘и ‘1’. Вторым результатом умножение ’25’ * ’30 ‘, третьим ’30’-’10’. Индексы могут задаваться не только с помощью выражений, но и с помощью переменных:
LastIndex.l = 2
FirstIndex.l = 0
Dim StringArray.s(LastIndex)
StringArray(FirstIndex) = «One is one and all alone»
StringArray(FirstIndex + 1) = «Two, two, the lily-white boys»
StringArray(FirstIndex + 2) = «Three, three, the rivals»
Debug StringArray(FirstIndex)
Debug StringArray(FirstIndex + 1)
Debug StringArray(FirstIndex + 2)Здесь мы определили массив с тремя индексами, каждый из которых содержит строковую переменную(обратите внимание на суффикс .s). С помощью переменной LastIndex мы сумели задать три индекса. Затем мы использовали переменную FirstIndex чтобы заполнить массив тремя переменными. Далее попросту считали данные из массива в отладочное окно. См. таблицу ниже для большего понимания соответствия индексов и значений:
Индекс Значение One is one and all alone
Two, two, the lily-white boys Three, three, the rivals Поскольку массивы аккуратно отсортированы в индексы, это дает возможность для перебора их с помощью циклов, очень быстро. Вот пример массива с 1000 индексами.
Сначала с помощью первого цикла мы заполняем массив, а вторым циклом считываем данные из массива в окно отладки.Dim TestArray.l(999)
For x = 0 To 999
TestArray(x) = x
Next x
For x = 0 To 999
Debug TestArray(x)
Next xЗапустите код и посмотрите в окно отладки. Как вы можете видеть, с помощью циклов легко и быстро заполнить массив, а потом так же быстро считать из массива.

Многомерные массивы
Лучший способ описать многомерные массивы,это создать таблицу.Чтобы понять как размещаются данные, мы
просто укажем число столбцов и строк, которые имеет массив.(Но это чуть ниже). А сейчас посмотрим пример
где создадим массив,так называемый » Animals «,который состоит из трех индексов,каждый из которых содержит
еще три индекса.Dim Animals.s(2, 2)
Animals(0, 0) = «Sheep»
Animals(0, 1) = «4 Legs»
Animals(0, 2) = «Baaa»Animals(1, 0) = «Cat»
Animals(1, 1) = «4 Legs»
Animals(1, 2) = «Meow»Animals(2, 0) = «Parrot»
Animals(2, 1) = «2 Legs»
Animals(2, 2) = «Screech»Debug Animals(0, 0) + » has » + Animals(0, 1) + » And says » + Animals(0, 2)
Debug Animals(1, 0) + » has » + Animals(1, 1) + » And says » + Animals(1, 2)
Debug Animals(2, 0) + » has » + Animals(2, 1) + » And says » + Animals(2, 2)И так давайте посмотрим в обещанную таблицу, в которой все наглядно видно и понятно:
Индекс 0 1 2 Sheep 4 Legs Baaa
Cat 4 Legs Meow Parrot 2 Legs Screech Из таблицы видно, как располагаются данные в массиве.
Допустим мы хотим сменить данные в нулевой строке. Тогда так:
Animals(0, 0) = «Tripod»
Animals(0, 1) = «3 Legs»
Animals(0, 2) = «Oo-la»В итоге будет следующее:
Индекс 0 1 2 Tripod 3 Legs Oo-la
Cat 4 Legs Meow Parrot 2 Legs Screech Еще один способ объяснить многомерные массивы в том, что их принцип массив в массиве . Вспомним, что
в каждом массиве индекса содержится другой массив, и вы получите идею многомерных массивов.
В следующем примере показано , как определить один, два, три, четыре и пятьмерных массивов:Dim Animals.s(5)
Dim Animals.s(5, 4)
Dim Animals.s(2, 5, 3)
Dim Animals.s(1, 5, 4, 5)
Dim Animals.s(2, 3, 6, 2, 3)После двумерных массивов, трехмерные и т д, кажутся сложными, но если вы вспомните, массив
в массиве , то становится более менее понятно. Хотя максимальный ряд аспектов, который
может быть отнесен к элементам массива двести пятьдесят пять (255), использование массивов
более двух или более трех измерениях необычное в повседневной практике программирования.
Структурированный тип массивов
До сих пор мы видели, как применять различные массивы, используя только стандартные средства, но у нас есть
возможность применять массивы, используя структуру. Давайте рассмотрим простой пример использования одномерного массива:Structure FISH
Kind.s
Weight.s
Color.s
EndStructureDim FishInTank.FISH(2)
FishInTank(0)\Kind = «Clown Fish»
FishInTank(0)\Weight = «4 oz.»
FishInTank(0)\Color = «Red, White and Black»
FishInTank(1)\Kind = «Box Fish»
FishInTank(1)\Weight = «1 oz.»
FishInTank(1)\Color = «Yellow»
FishInTank(2)\Kind = «Sea Horse»
FishInTank(2)\Weight = «2 oz.»
FishInTank(2)\Color = «Green»Debug FishInTank(0)\Kind+» «+FishInTank(0)\Weight+» «+FishInTank(0)\Color
Debug FishInTank(1)\Kind+» «+FishInTank(1)\Weight+» «+FishInTank(1)\Color
Debug FishInTank(2)\Kind+» «+FishInTank(2)\Weight+» «+FishInTank(2)\ColorПосле того как мы определили структуру FISH , мы определили массив, используя команду DIM, а суффикс FISH — тип массива.
Все так же, как мы использовали .S (string) в массиве Animals . Кроме того мы использовали ‘2’ в качестве последнего индекса в этом массиве.
Для присвоения значений полей каждому индексу массива, надо просто объединить синтаксис задания массивов и структур:FishInTank(0)\Kind = «Clown Fish»
Давайте попробуем разбить эту часть кода на куски для большего понимания. Во-первых, имя массива, в данном случае это
» FishInTank . Затем идет текущий индекс, содержащийся в скобках, в данном случае индекс ‘0 ‘. Далее мы используем
символ ‘\’ для доступа к области, называемой » KIND » в пределах FISH структуры, которая была возложена на массив
FishInTank . Затем мы используем оператор ‘=’, чтобы присвоить строковое значение. Для получения значения, которое мы только что назначили,
мы просто используем точно такой же синтаксис, как при назначении. В данном случае мы выводим значение в окно отладки:Если нам необходимо получить и другие значения индексов массива, мы делаем это так:
Debug FishInTank(0)\Kind
Debug FishInTank(1)\Kind
Debug FishInTank(2)\KindЭто был список полей Kind всех индексов массива FishInTank . Чтобы получить значение из других областей,
мы просто используем их имена:Debug FishInTank(1)\Kind
Debug FishInTank(1)\Weight
Debug FishInTank(1)\ColorЗдесь мы получаем все поля, одного из индексов массива ‘1 ‘. Чтобы было более понятно давайте опять создадим графическую таблицу
Индекс Структура FISH Kind: Clown Fish Weight: 4 oz. Colour: Red, White and Black
Kind: Box Fish Weight: 1 oz. Colour: Yellow Kind: Sea Horse Weight: 2 oz. Colour: Green Как и в случае с одномерными массивами, вы можете указать многомерные массивы с помощью структуры. Вы получите доступ к полям структуры в рамках каждого из индексов внутри многомерных массивов. Чтобы определить многомерный структурированный тип массива, делайте это в точности так же, только дополнив индексы.
Structure FISH
Kind.s
Weight.s
Color.s
EndStructure
Dim FishInTank.FISH(2, 2)
.Я не буду набирать код массива, думаю и так все понятно, что следует вместо многоточия. С другой стороны мы создадим таблицу многомерного массива.
Индекс 0 1 2 Kind: Clown Fish
Weight: 4 oz.
Colour: Red, White and BlackKind: Box Fish
Weight: 1 oz.
Colour: YellowKind: Sea Horse
Weight: 2 oz.
Colour: Green
Kind: Parrot Fish
Weight: 5 oz.
Colour: RedKind: Angel Fish
Weight: 4 oz.
Colour: OrangeKind: Shrimp
Weight: 1 oz.
Colour: PinkKind: Gold Fish
Weight: 2 oz.
Colour: OrangeKind: Lion Fish
Weight: 8 oz.
Colour: Black and WhiteKind: Shark
Weight: 1 lb.
Colour: GreyДля получения значения из этого вида массива мы должны указать в скобках два индекса, то есть так:
Debug FishInTank(1, 1)\Kind
Если мы хотим изменить данные в массиве, то это можно сделать так:
FishInTank(1, 1)\Kind = “Devil Fish”
FishInTank(1, 1)\Weight = “6 oz.”
FishInTank(1, 1)\Color = “Dark Red”Мы изменили все поля структура FISH , которые расположены в средней части массива под индексом ‘1, 1 ‘. Смотрим ниже:
Индекс 0 1 2 Kind: Clown Fish
Weight: 4 oz.
Colour: Red, White and BlackKind: Box Fish
Weight: 1 oz.
Colour: YellowKind: Sea Horse
Weight: 2 oz.
Colour: Green
Kind: Parrot Fish
Weight: 5 oz.
Colour: RedKind: Devil Fish
Weight: 6 oz.
Colour: Dark RedKind: Shrimp
Weight: 1 oz.
Colour: PinkKind: Gold Fish
Weight: 2 oz.
Colour: OrangeKind: Lion Fish
Weight: 8 oz.
Colour: Black and WhiteKind: Shark
Weight: 1 lb.
Colour: GreyВы, вероятно, используете только одномерные структурированные массивы в ваших программах на данный момент, но знайте, что многомерные массивы структурированного типа дадут вам хорошее представление о более расширенном коде.

Переопределение созданного массива
Стандартные массивы в PureBasic не статичны, то есть они могут быть переопределены двумя разными способами. Первый способ заключается в использовании команды Dim которая переопределяет массив, но в процессе уничтожает все предыдущие данные, имеющиеся в нем. Второй способ заключается в использовании команды ReDim, которая переопределяет массив, но сохраняет предыдущие данные нетронутыми. Давайте посмотрим на переопределение массива с помощью команды Dim:
Dogs(0) = «Jack Russell»
Dogs(1) = «Alaskan Husky»
Dogs(2) = «Border Collie»Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)Debug Dogs(0)
Debug Dogs(1)
Debug Dogs(2)Здесь после создания и заполнения массива, мы переопределив его попросту стираем все данные в нем. Это может быть очень полезно. К примеру надо очистить лишнюю используемую память после массива.Но знайте, что переопределяя массив, надо применять тот же тип, иначе будет ошибка. А теперь давайте воспользуемся командой ReDim и переопределим массив, дополнив его, причем старые данные сохранятся:
Dogs(0) = «Jack Russell»
Dogs(1) = «Alaskan Husky»
Dogs(2) = «Border Collie»For x.l = 0 To 2
Debug Dogs(x)
Next xDogs(3) = «Yorkshire Terrier»
Dogs(4) = «Greyhound»For x.l = 0 To 4
Debug Dogs(x)
Next xВ примере выше мы дополнили массив двумя ячейками, в результате их стало пять.
Правила пользования массивов
Хотя массивы являются очень гибкими, существует несколько правил, которые должны учитываться при их использовании.
Правила должны быть соблюдены при использовании массивов в своих программах.1. Если массив повторно определяется с помощью команды Dim, массив теряет свои предыдущие данные.
2. Если массив повторно определяется с помощью команды ReDim, то предыдущие данные сохраняются.
3. Массивы могут быть сделаны только из одного типа переменной (структурированного или стандартного типа переменной).
4. Массивы могут быть глобальными(Global), защищенной(Protected), статические(Static) и общие(Shared) (. См. главу 6 ).
5. Размер массива ограничен только оперативной памятью текущей машины.
6. Многомерные массивы могут иметь размер 255.
7. Массивы можно динамически определить с помощью переменной или выражения указывая размер.
8. При определении размера , вы определяете последний номер, а отсчет начинается с нуля.
9. Индексы могут быть различных размеров в многомерных массивах.Статические массивы в структурах
Статические массивы в структурах немного отличаются от обычных массивов, которые были
описаны ранее. Статические массивы в самой своей природе являются статичными и поэтому не могут быть изменены, после того, как они определены. Эти типы массивов существуют только в рамках структуры.
Статические массивы также имеют различный набор правил, которые учитывается при их использовании:1. Как только статический массив определен, его внутренняя структура не может быть изменена.
2. Статические массивы (как структуры) не могут быть переопределены.
3. Они могут быть сделаны только из одного типа переменной (структурированного или стандартного типа переменной).
4. Размер массива ограничен только установленной оперативной памятью текущей машины.
5. У статических массивов может только быть одна размерность.
6. Они могут быть динамически определены, используя переменную или выражение, в которой задается размер
7. При определении размера , вы определите кол-во индексов и оно показывает реальный размер массива.
8. Статические массивы могут быть доступны только через структуру переменных, в которых они определены.После того как я дал вам основные правила, позвольте мне привести вам пример того, как они используются:
Structure FAMILY
Father.s
Mother.s
Children.s[2]
Surname.s
EndStructureFamily.FAMILY
Family\Father = «Peter»
Family\Mother = «Sarah»
Family\Children[0] = «John»
Family\Children[1] = «Jane»
Family\Surname = «Smith»Debug «Family Members:»
Debug Family\Father + » » + Family\Surname
Debug Family\Mother + » » + Family\Surname
Debug Family\Children[0] + » » + Family\Surname
Debug Family\Children[1] + » » + Family\SurnameВ этом примере, структура » FAMILY » имеет поле с названием » Children «, которое представляет собой статический строковой массив.
Когда мы определили этот массив, мы использовали цифру ‘2 ‘. Это означает, что в массиве два индекса.
Это не похоже на стандартные массивы, в котором вы определяете последний индекс.
В нашем новом статическом массиве два показателя, ‘0 ‘и ‘1’.
Далее в примере я назначил значения всех полей в структурированную переменную FAMILY , в том числе и два индекса в Children статического массива.
Вы заметите, что статические массивы имеют немного другой синтаксис для назначения и используют квадратные скобки:Вы также заметили, что вам не нужно использовать команду Dim, когда вы определяете статический массив. Вы просто добавляете квадратные скобки . В квадратных скобках вы определяете нужный размер. В структуре FAMILY выше, я использовал строковой тип для статического массива, но вы можете использовать любой тип и конечно же любую структуру.
Давайте рассмотрим еще один простой пример:Structure EMPLOYEES
EmployeeName.s
EmployeeClockNumber.l
EmployeeAddress.s
EmployeeContactNumbers.l[2]
EndStructureCompany(0)\EmployeeName = «Bruce Dickinson»
Company(0)\EmployeeClockNumber = 666
Company(0)\EmployeeAddress = «22 Acacia Avenue»
Company(0)\EmployeeContactNumbers[0] = 0776032666
Company(0)\EmployeeContactNumbers[1] = 0205467746
Company(1)\EmployeeName = «Adrian Smith»
Company(1)\EmployeeClockNumber = 1158Здесь я создал структуру под названием EMPLOYEES , чтобы описать небольшую компанию сотрудников.
Затем создал стандартный массив, который содержит десять таких записей. Внутри структуры EMPLOYEES я использовал статический массив с типом Long для хранения двух номеров контактного телефона.
Ну и начал определять индивидуальные сведения о сотрудниках, начинающихся с Company(0) \ . , затем Company(1) \ . , и т.д.
Я не завершил этот пример, но я уверен, что вы поняли идею того,что я хотел показать.Связанные списки похожи на массивы тем, что они могут сослаться на множество данных с использованием одного имени.
Вместе с тем, они отличаются от массивов тем, что они не используют индекс чтобы назначать и получать данные.
Эти списки похожи на книгу, в которой вы можете пролистать данные от начала до конца или просто перейти к нужной странице внутри, ну и конечно считать данные оттуда. Связные списки полностью динамичны. Это означает, что они могут расти или уменьшаться в зависимости от того, сколько данных вам нужно хранить в них. При увеличении размеров в связанных списках не будет вреда. Кроме того, если вам надо добавлять или изменять какие-либо другие данные, хранящиеся в них, вы можете спокойно это делать, не боясь за остальные данные, причем в любом месте связанного списка.Связные списки являются отличным способом хранения и управления данными неопределенной длины и могут быть отсортированы несколькими способами. Существует также встроенные библиотеки, которые предоставляют функции для выполнения команд добавления, удаления и замены элементов. Так же внутри библиотеки имеются две функции, которые используются исключительно для сортировки связанных списков, но об этом я упомяну позже.Общий обзор встроенных команд, будет дан позднее в главе 7.
Связанные списки в PureBasic создаются с помощью функции NewList , как в следующем примере:
Определение связанного списка очень похоже на определение массива, используя команду Dim . В начале мы используем команду NewList , чтобы сообщить компилятору, что мы собираемся определить связанный список. Далее, мы определяем имя нашего списка, в данном случае мы называли это Fruit . После названия мы определяем его тип, в нашем случае String то есть строковой. Скобки используются для определения списка. В них не надо ничего заносить, поскольку списки динамичны и будут расти по мере добавления элементов. Давайте посмотрим, как мы добавим новый элемент в список:
NewList Fruit.s()
AddElement(Fruit())
Fruit() = «Banana»
AddElement(Fruit())
Fruit() = «Apple»Поскольку связанные списки не имеют индексов, использование их на первый взгляд кажется странным, потому что неизвестно где какой элемент расположен. В приведенном выше примере я добавил два новых элемента в список Fruit() .
Для этого я использовал функцию AddElement() . Когда мы добавляем новый элемент, с помощью этой функции,она не только автоматически определяет новый элемент, но также делает связанную точку в списке имен,создавая пустой элемент.
А дальше мы просто используем имя списка, чтобы присвоить этому элементу часть нужных нам данных в список.
Вместе с именем списка обязательно используем круглые скобки:Когда мы добавляем еще один элемент помощью функции AddElement() , то происходит точно такой же процесс:
Можно подумать, что это неправильно, потому что мы присваиваем текст Apple тому же имени, которому присвоили текст Banana . Но если вспомнить, что мы каждый раз добавляем новый элемент связанного списка с помощью функции AddElement() , при всем этом сохраняя старые,то думаю все становится понятным. Мы всегда можем проверить, сколько элементов в нашем списке, используя функцию CountList() например:
Если вы выполнили код выше, и дописали туда Debug CountList(Fruit()) то количество элементов, в списке Fruit() будет показано в окне отладки и равно 2.
Давайте добавим побольше элементов в этот список, а затем с помощью цикла выведем их в окно отладки:
NewList Fruit.s()
AddElement(Fruit())
Fruit() = «Banana»
AddElement(Fruit())
Fruit() = «Apple»
AddElement(Fruit())
Fruit() = «Pear»
AddElement(Fruit())
Fruit() = «Orange»
ForEach Fruit()
Debug Fruit()
NextВ этом примере, мы создали новый связанный список, называемый Fruit() и в нем мы создали четыре элемента и назначили им индивидуальные значения. Затем используя цикл ForEach мы вывели эти значения в окно отладки.
Команда ForEach используется для определения цикла, который используется только для связанных списков.Ниже дается краткий обзор команд для связанных списков.
Более продвинутые команды могут быть найдены в PureBasic Helpfile.Функция Описание AddElement(List()) Добавляет элемент в список. ClearList(List()) Очищает список всех элементов. CountList(List()) Подсчитывает кол-во элементов внутри списка. DeleteElement(List()) Удаление текущего элемента в списке FirstElement(List()) Перейти к первому элементу в списке. InsertElement(List()) Вставляет один элемент в список перед текущим элементом, или в начало списка, если список пуст. LastElement(List()) Переход к последнему элементу в списке. ListIndex(List()) Возвращает позицию текущего элемента в списке. (позиция начинается с ‘0’). NextElement(List()) Переход к следующему элементу в списке. PreviousElement(List()) Переход к предыдущему элементу в списке. ResetList(List()) Сбросить позиции списка в ‘0 ‘и сделать первый элемент текущим. SelectElement(List(), Position) Сделать текущим элементом тот, что указан в параметре ‘Position’. 
Структурированные Связные списки
Теперь, когда я объяснил стандартные связанные списки, давайте перейдем к структурированным. Они аналогичны структурированным массивам в том, что данные определяются с помощью структуры вместо встроенных переменных. Давайте возьмем пример с структурированными массивами, но переделаем код под структурированные связанные списки.
Structure FISH
Kind.s
Weight.s
Color.s
EndStructureNewList FishInTank.FISH()
AddElement(FishInTank())
FishInTank()\Kind = «Clown Fish»
FishInTank()\Weight = «4 oz.»
FishInTank()\Color = «Red, White and Black»
AddElement(FishInTank())
FishInTank()\Kind = «Box Fish»
FishInTank()\Weight = «1 oz.»
FishInTank()\Color = «Yellow»
AddElement(FishInTank())
FishInTank()\Kind = «Sea Horse»
FishInTank()\Weight = «2 oz.»
FishInTank()\Color = «Green»
ForEach FishInTank()
Debug FishInTank()\Kind+» «+FishInTank()\Weight+» «+FishInTank()\Color
NextВы можете видеть из этого примера, что после создания списка, он очень похож на структурированный массив. Основное различие здесь в том, что индексы массива не используются. Помните, что при использовании AddElement(FishInTank()) команда создает новый элемент с использованием структуры. Обратите внимание, нам не надо каждый раз писать
AddElement(FishInTank()) .
Вот в чем прелесть структуры! Она расширяет наш код, притом в очень удобном виде.Связанные списки за или против?
Связные списки прекрасно подходят для хранения данных, когда вы не знаете, сколько их будет. Например ранее я написал программу для отслеживания бытовых расходов, и использовал структурированные связанные списки.
Подробная информация об этих расходах. Использование связанного списка, было более удобным, чем массив, поскольку проще простого было добавлять, удалять и сортировать данные.
Во время написания этой программы я думал, что я должен сделать эту программу гибкой, чтобы работать с новыми расходами когда они встречаются, и чтобы иметь возможность удалить старые
и т.д.
Это очень хорошо обрабатывается в связанных списках. Когда мне нужно добавить запись я использую функцию AddElement() , когда мне нужно удалить запись я использую функцию DeleteElement() . После добавления и удаления в списке, я передаю все эти данные в приятный графический интерфейс пользователя (GUI) чтобы увидеть и взаимодействовать. Более подробно о GUI в главе 9.
Связные списки являются более гибкими, чем массивы в том, что они могут расти и уменьшаться в размерах более быстро и просто.
Массивы же всегда будет использовать меньше памяти для хранения того же объема информации, чем связанные списки. Это происходит потому, что массивы используют непрерывную область памяти, используя стандартный объем оперативной памяти для каждого индекса. Связные списки отличаются таким образом, чтобы каждый элемент использует примерно в три раза больше
RAM для определенного типа. Это происходит потому,что связанные списки не находятся в непрерывном куске памяти.
Имейте в виду при работе с огромными массивами данных, так как ваши требования к памяти могут быть тройными, если вы будете использовать связанные списки.Сортировки массивов и связанных списков
Массивы и связанные списки прекрасно подходят для хранения всех видов данных, и эти данные проходящие через структуры могут быть легко получены. Хотя иногда вам может потребоваться реорганизовать данные содержащиеся в массиве или связанном списке в алфавитном порядке или численно. Есть несколько примеров (Helpfile:Reference Manual->General Libraries->Sort)
для сортировки массивов и связанных списков.Сортировка стандартных массивов
Сортировка стандартных массивов чрезвычайно проста. Прежде всего, вам необходимо иметь массив с заполнеными значениями.
Затем использовать функцию SortArray() для сортировки. Вот примерный синтаксис:SortArray(Array(), Options [, Start, End])
Первым делом мы задаем команду SortArray, , что массив будет отсортирован. Обратите внимание за фигурными скобками после имени массива стоят еще одни скобки.
Они необходимы для правильной передачи массива в качестве параметра. Второй параметр является опциональным, чтобы указать, как массив будет отсортирован.
Вот опциональные значения для второго параметра:‘0 ‘: Сортировка массива в порядке возрастания быть чувствительным к регистру.
‘1 ‘: Сортировка массива в порядке убывания быть чувствительным к регистру.
‘2 ‘: Сортировка массива в порядке возрастания, не быть чувствительным к регистру.
(‘ A ‘такой же, как ‘ а ‘).
‘3 ‘: Сортировка массива в порядке убывания, не быть чувствительным к регистру.
(‘ A ‘такой же, как ‘ а ‘).Квадратные скобки, с последними двумя параметрами показывают, что эти не являются обязательными. Последние два параметра используются для указания позиции внутри массива.Используя выше информацию, мы можем сортировать массив в порядке возрастания и быть чувствительным к регистру, с использованием
команды SortArray(Fruit(), 0) :Dim Fruit.s(3)
Fruit(0) = «Banana»
Fruit(1) = «Apple»
Fruit(2) = «Pear»
Fruit(3) = «Orange»
SortArray(Fruit(), 0)For x.l = 0 To 3
Debug Fruit(x)
Next xСортировка структурированных массивов
Это будет посложнее, поскольку она использует немного более сложную команду сортировки SortStructuredArray() .
Вот примерный синтаксис:SortStructuredArray(Array(), Options, Offset, Type [, Start, End])
Первым параметром является имя массива со скобками. Вторым способ сортировки, это
точно так же, как в SortArray() . Третим параметром является смещение (позиция в теле
структуры) то есть поле, которое вы хотели бы сортировать. Можно задавать с помощью функции OffsetOf()
Функция OffsetOf() возвращает количество байт какой-либо переменной от начала структуры. Четвертый параметр определяет, какой тип переменной находится на месте смещения. Вы можете использовать встроенные константы для указанных параметров, для описания типа переменной:Последние два параметра в скобках, точно так же как и SortArray (). А теперь пример:
Structure WEAPON
Name.s
Range.l
EndStructureDim Weapons.WEAPON(2)
Weapons(0)\Name = «Phased Plasma Rifle»
Weapons(0)\Range = 40
Weapons(1)\Name = «SVD-Dragunov Sniper Rifle»
Weapons(1)\Range = 3800
Weapons(2)\Name = «HK-MP5 Sub-Machine Gun»
Weapons(2)\Range = 300SortStructuredArray(Weapons(), 0, OffsetOf(WEAPON\Range), #PB_Sort_Long)
For x.l = 0 To 2
Debug Weapons(x)\Name + » : » + Str(Weapons(x)\Range)
Next xВ этом примере я выбрал поле » Range «, чтобы упорядочить структурированный массив.В команде SortStructuredArray
я определил смещение с помощью функции OffsetOf (WEAPON\Range) и указал тип переменной поля с помощью константы #PB_Sort_Long .Сортировка стандартного связанного списка
Сортировка стандартных связанных списков предельно проста. Прежде всего, вам потребуется связанный список предварительно заполненный
значениями. Затем использовать функцию SortList() для сортировки. Вот примерный синтаксис:SortList(ListName(), Options [, Start, End])
Вначале идет название функции, и оно говорит о том что связанный список будет отсортирован. Далее в скобках задаются параметры:
1) Имя связанного списка со скобками
2) Опция сортировки (так же как у массивов выше)
3) Необязательные параметры начала и конца сортировки внутри спискаКак вы успели заметить все достаточно схоже с массивами, разница лишь в имени функции!
Использовав приведенную выше информацию, мы отсортируем список в возрастающем порядке с опцией: чувствительность к регистру:
NewList Fruit.s()
AddElement(Fruit())
Fruit() = «Banana»
AddElement(Fruit())
Fruit() = «Apple»
AddElement(Fruit())
Fruit() = «Orange»ForEach Fruit()
Debug Fruit()
NextСортировка структурированных связанных списков
Сортировка структурированых связанных списков как и массивов немного сложнее, поскольку она использует немного более сложную функцию SortStructuredList() для сортировки. Вот пример синтаксиса этой команды:
SortStructuredList(List(), Options, Offset, Type [, Start, End])
Первой идет имя функции SortStructuredList() Далее в скобках задаются параметры:
1. Имя списка
2. Опция сортировки(так же как у массивов выше)
3. Смещение в структуре, то есть нужное поле(задается с помощью функции OffsetOf() )
4. Тип переменной, которая хранится в нужном поле структуры (можно задавать константой, см. выше список констант)
5. Необязательные параметры начала и конца сортировки внутри спискаНу и конечно пример:
Structure GIRL
Name.s
Weight.s
EndStructureNewList Girls.GIRL()
AddElement(Girls())
Girls()\Name = «Mia»
Girls()\Weight = «8.5 Stone»
AddElement(Girls())
Girls()\Name = «Big Rosie»
Girls()\Weight = «19 stone»
AddElement(Girls())
Girls()\Name = «Sara»
Girls()\Weight = «10 Stone»
SortStructuredList(Girls(), 0, OffsetOf(GIRL\Name), #PB_Sort_String)ForEach Girls()
Debug Girls()\Name + » : » + Girls()\Weight
NextВ этом примере я выбрал поле «Name» для сортировки структурированного связанного списка. Определить смещение мне помогла функция OffsetOf(Girl \ Name) , а тип переменной я задал с помощью константы #PB_Sort_String .
Как маленькое заключение по массивам и спискам
Выбор массивов, связанных списков, структур должен зависеть от задачи поставленной программистом. Хотя зачастую на практике, каждый программист любит работать с более привычными для него методами хранения данных, на мой взгляд надо все же уметь выбирать для каждой задачи более уместный метод.
Сортировка массивов и связанных списков, созданных с помощью структур или без них, требует правильности синтаксиса, нужных функций и главное вашей практики. Попрактикуйтесь, и вы быстро овладеете этим в принципе нехитрым, но мощным оружием в программировании.
PureBasic форум http://purebasic.info/phpBB2/
Визуальный редактор Visual web
Перевод: Станислав Будинов
GetDatabaseBlob()
Zoom in on the sample code above, and look for these three lines:
The second parameter of GetDatabaseBlob() speficies the table column number. This is NOT the same as the ‘index’ used by SetDatabaseBlob().
DatabaseColumnSize()
The command DatabaseColumnSize() returns the size of the specified column of the selected row. This means you can insert a blob and later retrieve first the blob size, allocate memory, then retrieve the blob data using the following approach:
You can have multiple databases, and multiple tables. It is possible to retrieve information on a table, but this only works after you have executed a SELECT statement.
The code below uses DatabaseColums() to retrieve the number of columns, then shows the name of each column using the DatabaseColumnName() command.
Note to self: check and expand.
I f an SQL database is an essential part of your solution, you should consider PostgreSQL. MySQL has some license issues, and needs an ODBC connector.
MySQL is one of the most well-known SQL server packages. Note that there is dispute about the usability / legality in a commercial environment, due to some license restrictions. It appears to me that you can use it, but that you will have to use ODBC to avoid license issues. You may consider PostgreSQL as an alternative.
Again, this is not a tutorial on SQL, MySQL, or ODBC. I’m only interested in setting things up so I can use PureBasic to mess around with them 🙂 Still it is worth it to have another look at the issue in case we’d become too succesful 🙂
Some notes on the license issue. I’m not a lawyer (otherwise I would be working for a patent troll, be indencently rich, and not be writing this :-)) so take the following at face value. In other words, my humble opinion, your mileage may vary, at your own risk, disclaimers etc. etc. etc.
Unless you BUY a license of MySQL you need to adhere to the GPL. As far as I can tell nothing is going to stop you from using MySQL in a non-commercial or commercial project, as long as you adhere to the license. The key is the term ‘derivative work’.
1. Embedding GPL’ed SOURCE in your code would clearly force you to use the GPL license for your whole product.
2. STATIC LINKING of a GPL’ed library makes the GPL’ed code and resulting program part of your program and thus forces you to use the GPL license.
3. DYNAMIC LINKING is a bit more tricky. Strictly spoken the functionality of the DLL becomes part of your program, but the code itself does not. The jury is still out on this one. If your program would use functionality exposed by an under GPL developed and distributed DLL, which DLL was developed and distributed for such a purpose, and which DLL is not distributed as part of your program, then you’re probably not obliged to go GPL. However, it’s inside the grey zone.
4. If the whole GPL’ed program is an integral element of your solution, and you would install it (perhaps automatically) as part of your (commercial) solution, you’d be entering the grey zone as well. Most definitely if you would hide such an installation from the user (as part of a commercial package).
The above doesn’t stop you from using MySQL. Using functionality provided / exposed by MySQL ODBC connector software, or communicating with the MySQL server is not considered derivative work so should be fine. You (probably) cannot automagically install MySQL and / or the MySQL ODBC connector, and you (definitely) cannot embed a MySQL library in your program. But nothing is going to stop you from installing or using a MySQL platform as part of a commercial and / or non-GPL’ed solution, it just cannot be part of your program.
The above was written in 2010. Who knows what has changed since then, so go and check that license before doing something stupid 🙂
13.22 Installation server side.
You might want to run this on a dedicated machine, server, or virtual machine. I used VirtualBox to setup such a ‘dedicated’ MySQL server on a virtual machine. Read more about using VirtualBox here. MySQL needs one side to be a server, and the other to be a client, but nothing is stopping you to install server and client software on the same machine. (Frankly, if you’re just going to use MySQL as a simple local database, there’s very little reason to use a dedicated machine, but then again why are you not using SQLite then?)
There are complete packages around including tools, configuration etc. such as Xampp. They may make your life easier, especially if you’re interested in building applications for the web. I may revisit Xampp once I find the courage to use PureBasic for web applications. For now, it’s though enough as it is 🙂
Machine and Windows
Create a VM if you’re going to use VirtualBox or something similar. You may consider assigning a fixed IP to your server. I changed the name of my dedicated MySQL server to ‘sqlserver’.
MySQL 5.1.38 and MySQL Essentials 5.1
1. Download the MySQL server essentials package and install it. I used 5.1 and ticked the option ‘custom’ as I like to think of myself as an expert (which, obviously, I am not :-)). Note: when reinstalling MySQL it couldn’t start the service, no matter what I tried. In the end, I cloned a new VM and reinstalled. (I should have used a snapshot in VirtualBox but I forgot to create one :-)) I think I messed up a password which wasn’t removed during de-installation, but that’s the good thing about imaging and / or virtual machines. restoring is a lot easier.
2. The default port is 3306. Tick the box ‘add firewall exception’ if you’re using Windows firewall. Note: this may not suffice, and you might have to allow traffic manually! When in doubt, check functionality by shutting down the firewall temporary. Oh, and if you are using the host name on the client to find the server, enable ‘file and printer sharing’ on that server otherwise the client won’t find the host!
3. Tick ‘best support for multilingualism’. Install as a Windows service and have it launched automatically. Also tick the option ‘include bin directory in path’. Next etc.
4. Modify security settings and enter a new root password. For simplicity I used the password ‘root’ here. not very safe, but this is a test environment, not a production server. Next etc.
5. Hit the ‘execute’ button and hope it doesn’t crash during installation. (It did here twice. ) Next etc.
Tada. You’ve now got your own MySQL server up and running as a service on your virtual machine. Congratulations.
Don’t forget to open the appropriate port(s) in your firewall.
MySQL GUI Tools 5.0
Note: these seem to have been replaced by the MySQL Workbench.
These tools make your life a little easier, unless you’re a die-hard that likes the command prompt.
1. Download and install the GUI tools package and install it. I used 5.0 and did install all except the MySQL migration toolkit. Next, install, finish etc, you know the drill.
2. Under Windows Start / Programs you’ll find a new folder MySql. Start the MySQL Tray Monitor. Click on it with the RMB.
3. Switch ON the option Monitor Options / Launch Monitor After Login.
4. There’s another tool you’ll find there called MySQL Administrator. You may want to drag it onto the desktop for quick access.
You can now test your setup.
Note that you can install the MySQL GUI Tools on your clients, if you want to. Especially the MySQL Query Browser may come in handy if you want to experiment with the SQL language itself.
MySQL Workbench 5.2 CE
This seems to have replaced the MySQL GUI Tools. I’ve tried this one on a client to execute queries and it worked fine.
Adding a user
Start the MySQL Administrator on your new SQL server and log in as root. Select Use Administration / Add New User. I added a new user called ‘user’ with password ‘user’. (Yes, I’m a very creative person.)
Creating a database
Obvously, you should only create it once. executing CREATE DATABASE PUREBASIC a second time will throw an error. It already existed 🙂
In all future calls we might use the MySQL Query Browser with ‘default schema’ set to purebasic, we just needed that build-in ‘test’ database this one time to start up the query browser and create our own first database. The program is supposed to let us connect to the MySQL service without a database given, but I didn’t get through without one.
In the 2013 MySQL Workbench I received an error. Adding semicolons fixed it:
13.23 Installation client side
There is more than one way to talk to the MySQL server, but from within PureBasic the easiest one is using ODBC.
MySQL ODBC Connecter
1. Download the MySQL ODBC connector for Windows and run it.
2. Look for Start / Programs / Administrative Tools / Data Sources (ODBC) and start it. This tool may be located somewhere else on your machine, for example on my Windows 7 box it could be accessed via Control Panel / Data Sources (ODBC).
64 bit users be aware! There are TWO different versions of ODBC on your machine!
Typically if you run into the following error, you’re using the wrong one (mostly by trying to access the 64 bits ODBC from a 32 bits application):
Anyway, if things worked out well, you should be seeing something like this:
4. Hit the ‘Test’ button. If the ODBC connector cannot connect to our MySQL Server then most likely a firewall is causing the problem, either on the client or on the server. Try it with the firewalls turned off. If that works, you might test with the IP address of the server instead of its name, ortry
5. Run the program below. It should create a little table and produce the same results as our SQLite version.
Of course, you could also install the MySQL Workbench on your client machine, to verify the results of your code, and experiment with SQL queries outside of PureBasic.
13.24 SQLite to MySQL
From a PureBasic and SQL point of view there is little difference between MySQL and SQLite. It’s important to keep in mind that MySQL is more strict on data types.
In SQLite with a single user application you might skip BEGIN / COMMIT but in multi user applications in a network I would strongly advise to use them.
PostgreSQL is ‘the other’ open source database, but it doesn’t suffer from GPL issues. This means that PostgreSQL drivers / libraries can be linked with / embedded in other programs. Which is exactly what PureBasic did 🙂
You will always need to install PostgreSQL on the server side. You may chose to use ODBC on the client side, or use the onboard drivers of PureBasic.
I found the installation and configuration of MySQL marginally easer, and the MySQL GUI tools are nice, especially the MySQL Query Browser. However PostgreSQL contains a similar tool, and if you look around on the Internet you’ll find some alternatives, I’m sure.
13.26 Installation server side
PostgreSQL needs one side to be a server, and the other to be a client, but nothing is stopping you to install server and client software on the same machine. (Frankly, if you’re just going to use PostgreSQL as a simple local database, there’s very little reason to use a dedicated machine, but then again why are you not using SQLite then?)
Machine and Windows
Create a VM if you’re going to use VirtualBox or something similar. You may consider assigning a fixed IP to your server. I created a new VM and changed its name to ‘sqlserver’. In fact, I installed MySQL and ProgreSQL on the same VM without any problems.
PostgreSQL 8.4.1
1. Download PostgreSQL 8.4.1. Use the regular package and install it.
2. The default port is 5432. Choose eventual passwords wisely. (I did not, so ‘postgres’ it is, everywhere :-)) Install.
3. Look for a file called ‘pg_hba.conf’. It’s in the PostgreSQL folders somewhere. If your local network runs in the 192.168.0.x range, then you will have to add the following line:
5. You may want to put the link ‘Postgress pgAdmin III’ on your desktop for easy access.
6. Start up pgAdmin. Connect to (doubleclick) the PostgreSQL server (localhost port 5432 user postgres password postgres).
7. RMB on ‘databases’ and add a new database called ‘purebasic’.
Don’t forget to open the appropriate port(s) in your firewall.
The PostgreSQL query browser
PostgreSQL also includes a query browser. To use it do the following:
1. Start up pgAdmin.
2. Select ‘purebasic’ under ‘Databases’.
3. EIther select Tools / Query tool, or hit [Control] + [E]. Note that some commands that work under MySQL don’t work on PostgreSQL.
13.27 Installation client side
Seriously, you could do an ODBC client side install, but PureBasic already contains the PostgreSQL library, so there’s no real need.
Use the following code to check if your PostgreSQL setup is working:
Of course, I couldn’t help myself and had to try 🙂
1. Get the ODBC connector software, the one I used I found on the PostgreSQL website, under file browser / odbc / versions / msi / psqlodbc_08_04_0100.zip.
2. Unzip and install it.
2. Look for Start / Programs / Administrative Tools / Data Sources (ODBC) and start it. This tool may be located somewhere else on your machine.
6. Try the following program:
13.28 MS SQL Express 2008
Well, there should be no reason why not to try MicroSoft’s latest 🙂 unfortunately I’m running XP in the VM, so I can’t test it with 2012. Let’s try it with an older version then: SQL Express 2008 on Windows XP.
Server side
Unfortunately, it’s not as easy to setup. I’ve got no clue about all those MS SQL options, but the ones below got me started. Information on this page helped me to get started.
Note that I wanted explictly to communicate with the database via TCP, port, and SQL user / password. If you’re using NT authentication this just might be a lot easier.