File indexing completed on 2024-04-28 03:42:53

0001 /*
0002     SPDX-FileCopyrightText: 2008 Akarsh Simha <akarshsimha@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 // Program to convert star data stored in a MySQL database into
0008 // the binary file format used by KStars
0009 
0010 #define DB_TBL                "nomad"
0011 #define DB_DB                 "stardb"
0012 #define VERBOSE               1
0013 #define HTM_LEVEL             6
0014 #define NTRIXELS              32768 // TODO: Change if HTM Level Changes
0015 #define INDEX_ENTRY_SIZE      12
0016 #define MYSQL_STARS_PER_QUERY 1000000
0017 
0018 #include "binfile.h"
0019 
0020 #include <mysql/mysql.h>
0021 #include <sys/types.h>
0022 #include <stdlib.h>
0023 #include <stdio.h>
0024 #include <math.h>
0025 #include <string.h>
0026 
0027 /*
0028  * struct to store star data, to be written in this format, into the binary file.
0029  */
0030 
0031 typedef struct deepStarData
0032 {
0033     int32_t RA;
0034     int32_t Dec;
0035     int16_t dRA;
0036     int16_t dDec;
0037     int16_t B;
0038     int16_t V;
0039 } deepStarData;
0040 
0041 /*
0042  * Dump the data file header.
0043  *
0044  * WARNING: Must edit every time the definition of the deepStarData structures changes
0045  *
0046  * f : Data file handle
0047  */
0048 
0049 int writeDataFileHeader(FILE *f)
0050 {
0051     char ASCII_text[124];
0052     u_int16_t nfields;
0053     u_int32_t nindexes;
0054     int16_t endian_id   = 0x4B53;
0055     u_int8_t version_no = 1;
0056 
0057     if (f == NULL)
0058         return 0;
0059 
0060     nfields = 6;
0061 
0062     str2charv(ASCII_text, "KStars Star Data v1.0. To be read using the 32-bit starData structure only.", 124);
0063     fwrite(ASCII_text, 124, 1, f);
0064     fwrite(&endian_id, 2, 1, f);
0065     fwrite(&version_no, 1, 1, f);
0066     fwrite(&nfields, sizeof(u_int16_t), 1, f);
0067 
0068     writeDataElementDescription(f, "RA", 4, DT_INT32, 1000000);
0069     writeDataElementDescription(f, "Dec", 4, DT_INT32, 100000);
0070     writeDataElementDescription(f, "dRA", 2, DT_INT16, 10);
0071     writeDataElementDescription(f, "dDec", 2, DT_INT16, 10);
0072     writeDataElementDescription(f, "B", 2, DT_INT16, 100);
0073     writeDataElementDescription(f, "V", 2, DT_INT16, 100);
0074 
0075     nindexes = NTRIXELS;
0076     fwrite(&nindexes, sizeof(u_int32_t), 1, f);
0077 
0078     return 1;
0079 }
0080 
0081 int main(int argc, char *argv[])
0082 {
0083     /* === Declarations === */
0084 
0085     int ret, i, exitflag;
0086     long int lim;
0087 
0088     double Mag;
0089 
0090     unsigned long us_header_offset;
0091     unsigned long usf_trix_begin;
0092     unsigned long usf_trix_count;
0093     unsigned long ntrixels;
0094     int16_t maglim;
0095     u_int8_t htm_level;
0096     u_int16_t MSpT_unnamed;
0097 
0098     char query[512];
0099     u_int32_t current_trixel;
0100 
0101     /* File streams */
0102     FILE *f;       /* Pointer to "current" file */
0103     FILE *usf;     /* Handle to star data file */
0104     FILE *usfhead; /* Handle to star header file */
0105 
0106     /* deepStarData structure */
0107     deepStarData data;
0108 
0109     /* MySQL structures */
0110     MYSQL link;
0111     MYSQL_RES *result;
0112     MYSQL_ROW row;
0113 
0114     /* Check the number of arguments */
0115     if (argc <= 6)
0116     {
0117         fprintf(stderr, "USAGE %s DBUserName DBPassword DeepStarDataFile DeepStarHeaderFile DBName [TableName]\n",
0118                 argv[0]);
0119         fprintf(stderr, "The database used is a MySQL DB on localhost. The default table name is `nomad`\n");
0120     }
0121 
0122     /* == Open all file streams required == */
0123     /* Unnamed Star Handling */
0124     usf = fopen(argv[3], "wb");
0125     if (usf == NULL)
0126     {
0127         fprintf(stderr, "ERROR: Could not open %s [Deep Star Data File] for binary write.\n", argv[3]);
0128         return 1;
0129     }
0130 
0131     usfhead = fopen(argv[4], "wb");
0132     if (usfhead == NULL)
0133     {
0134         fprintf(stderr, "ERROR: Could not open %s [Deep Star Header File] for binary write.\n", argv[4]);
0135         fcloseall();
0136         return 1;
0137     }
0138 
0139     /* MySQL connect */
0140     if (mysql_init(&link) == NULL)
0141     {
0142         fprintf(stderr, "ERROR: Failed to initialize MySQL connection!\n");
0143         return 1;
0144     }
0145 
0146     ret = mysql_real_connect(&link, "localhost", argv[1], argv[2], argv[5], 0, NULL, 0);
0147 
0148     if (!ret)
0149     {
0150         fprintf(stderr, "ERROR: MySQL connect failed for the following reason: %s\n", mysql_error(&link));
0151         fcloseall();
0152         return 1;
0153     }
0154 
0155     if (mysql_select_db(&link, argv[5]))
0156     {
0157         fprintf(stderr, "ERROR: Could not select MySQL database %s. MySQL said: %s", argv[5], mysql_error(&link));
0158         fcloseall();
0159         mysql_close(&link);
0160         return 1;
0161     }
0162 
0163     if (VERBOSE)
0164         fprintf(stdout, "Size of deepStarData structure: %d\n", sizeof(deepStarData));
0165 
0166     /* Write file headers */
0167     writeDataFileHeader(usfhead);
0168     us_header_offset = ftell(usfhead);
0169 
0170     /* Leave space for / write a deep magnitude limit specification in the data files */
0171     maglim = (int)(-5.0 * 100);
0172     fwrite(&maglim, 2, 1, usf); // Bogus entry
0173 
0174     /* Write a HTM level specification in the data file */
0175     htm_level = HTM_LEVEL;
0176     fwrite(&htm_level, 1, 1, usf);
0177 
0178     /* Leave space for a specification of MSpT (Maximum Stars per Trixel) in the data files */
0179     MSpT_unnamed = 0;
0180     fwrite(&MSpT_unnamed, 2, 1, usf); // Bogus entry
0181 
0182     /* Initialize some variables */
0183     lim            = 0;
0184     exitflag       = 0;
0185     current_trixel = 0;
0186     usf_trix_count = 0;
0187     usf_trix_begin =
0188         2 + 1 +
0189         2; // The 2 + 1 + 2 is to leave space for deep magnitude limit, HTM Level and MSpT specification. TODO: Change this if things change.
0190     ntrixels = 0;
0191 
0192     /* Recurse over every MYSQL_STARS_PER_QUERY DB entries */
0193     while (!exitflag)
0194     {
0195         /* Build MySQL query for next MYSQL_STARS_PER_QUERY stars */
0196         sprintf(query,
0197                 "SELECT `Trixel`, `RA`, `Dec`, `dRA`, `dDec`, `B`, `V`, `UID` FROM `%s` ORDER BY `trixel`, `Mag` ASC "
0198                 "LIMIT %ld, %d",
0199                 (argc >= 7) ? argv[6] : DB_TBL, lim, MYSQL_STARS_PER_QUERY);
0200 
0201         if (VERBOSE)
0202         {
0203             fprintf(stderr, "SQL Query: %s\n", query);
0204         }
0205 
0206         /* Execute MySQL query and get the result */
0207         mysql_real_query(&link, query, (unsigned int)strlen(query));
0208         result = mysql_use_result(&link);
0209 
0210         if (!result)
0211         {
0212             fprintf(stderr, "MySQL returned NULL result: %s\n", mysql_error(&link));
0213             fcloseall();
0214             mysql_close(&link);
0215             return 1;
0216         }
0217 
0218         exitflag = -1;
0219 
0220         /* Process the result row by row */
0221         while (row = mysql_fetch_row(result))
0222         {
0223             /* Very verbose details */
0224             if (VERBOSE > 1)
0225             {
0226                 fprintf(stderr, "UID = %s\n", row[12]);
0227                 for (i = 0; i <= 14; ++i)
0228                     fprintf(stderr, "\tField #%d = %s\n", i, row[i]);
0229             }
0230 
0231             if (exitflag == -1)
0232                 exitflag = 0;
0233 
0234             /* Write index entries if we've changed trixel */
0235             u_int32_t new_trixel = atoi(row[0]);
0236             if (current_trixel != new_trixel)
0237             {
0238                 if (VERBOSE)
0239                 {
0240                     fprintf(stderr, "Trixel Changed from %d to %s = %d!\n", current_trixel, row[0], new_trixel);
0241                 }
0242                 while (new_trixel != current_trixel)
0243                 {
0244                     writeIndexEntry(usfhead, current_trixel,
0245                                     us_header_offset + NTRIXELS * INDEX_ENTRY_SIZE + usf_trix_begin, usf_trix_count);
0246                     usf_trix_begin = ftell(usf);
0247                     if (usf_trix_count > MSpT_unnamed)
0248                         MSpT_unnamed = usf_trix_count;
0249                     current_trixel++;
0250                     ntrixels++;
0251                     usf_trix_count = 0;
0252                     if (VERBOSE)
0253                     {
0254                         fprintf(stderr, "%d %d\n", current_trixel - 1, ntrixels);
0255                     }
0256                 }
0257                 if (VERBOSE)
0258                 {
0259                     fprintf(stderr, "Done writing trixel entry\n");
0260                 }
0261             }
0262 
0263             /* Initializations */
0264 
0265             usf_trix_count++;
0266             f = usf;
0267 
0268             /* Convert various fields and make entries into the deepStarData structure */
0269             str2int32(&data.RA, row[1], 6);
0270             str2int32(&data.Dec, row[2], 5);
0271             str2int16(&data.dRA, row[3], 3);
0272             str2int16(&data.dDec, row[4], 3);
0273             str2int16(&data.B, row[5], 3);
0274             str2int16(&data.V, row[6], 3);
0275 
0276             int16_t B = data.B;
0277             int16_t V = data.V;
0278 
0279             if (V == 30000)
0280             {
0281                 if (B - 1600 > maglim && B != 30000)
0282                 {
0283                     maglim = B - 1600;
0284                 }
0285             }
0286             else
0287             {
0288                 if (V > maglim)
0289                 {
0290                     maglim = V;
0291                 }
0292             }
0293 
0294             /* Write the data into the appropriate data file and any names into the name file */
0295             if (VERBOSE)
0296                 fprintf(stderr, "Writing UID = %s...", row[7]);
0297             fwrite(&data, sizeof(deepStarData), 1, f);
0298             if (VERBOSE)
0299                 fprintf(stderr, "Done.\n");
0300         }
0301         mysql_free_result(result);
0302         lim += MYSQL_STARS_PER_QUERY;
0303     }
0304 
0305     do
0306     {
0307         writeIndexEntry(usfhead, current_trixel, us_header_offset + NTRIXELS * INDEX_ENTRY_SIZE + usf_trix_begin,
0308                         usf_trix_count);
0309         usf_trix_begin = ftell(usf);
0310         usf_trix_count = 0;
0311         current_trixel++;
0312         ntrixels++;
0313     } while (current_trixel != NTRIXELS);
0314 
0315     if (ntrixels != NTRIXELS)
0316     {
0317         fprintf(stderr,
0318                 "ERROR: Expected %u trixels, but found %u instead. Please redefine NTRIXELS in this program, or check "
0319                 "the source database for bogus trixels\n",
0320                 NTRIXELS, ntrixels);
0321     }
0322 
0323     rewind(usf);
0324     fwrite(&maglim, 2, 1, usf);
0325     fwrite(&htm_level, 1, 1, usf);
0326     fwrite(&MSpT_unnamed, 2, 1, usf);
0327 
0328     fcloseall();
0329     mysql_close(&link);
0330 
0331     return 0;
0332 }